home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / twu1.zip / TWU1DOC.TXT < prev    next >
Text File  |  1991-06-06  |  155KB  |  3,677 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.                            ──────────────────────────────
  18.  
  19.                            INSIDE TURBO PASCAL UNIT FILES
  20.  
  21.                                Version 6.0 for MS-DOS
  22.                               Version 1.0 for WINDOWS
  23.  
  24.                            ──────────────────────────────
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.                                          by
  49.  
  50.                                   William L. Peavy
  51.  
  52.                                   ────────────────
  53.  
  54.                                     June 6, 1991
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.                                       ABSTRACT
  62.  
  63.             If you  want to  know what is in a .TPU (unit) file produced
  64.             by either  Version 1.0  of Turbo  Pascal for  Windows or  by
  65.             Version 6.0 of Turbo Pascal from Borland International, then
  66.             this paper  is for you.  It doesn't explain quite everything
  67.             since the  I  don't  have  access  to  secret  documents  or
  68.             anything like  that and since some of the data in .TPU files
  69.             just doesn't  have enough  auxiliary information to make its
  70.             role clear.   However,  it is possible to learn a great deal
  71.             about how Turbo Pascal organizes the information it needs to
  72.             refer to, and it is also possible to learn just what kind of
  73.             code the compiler produces.
  74.  
  75.             This is  the fourth in a series of reports on the subject of
  76.             Turbo Pascal Units, the previous reports treating with Turbo
  77.             Pascal Versions  5.0 through  6.0.   The evolution  of these
  78.             files  in   the  face  of  changing  requirements  has  been
  79.             fascinating to  behold and  deciphering their  contents  has
  80.             been challenging to say the least.
  81.  
  82.             The programs supplied with this report have been reorganized
  83.             from their 6.0 style and many identifiers have been changed.
  84.             There are also a few bug fixes and algorithm changes.  Other
  85.             changes were  dictated by  the changes in the utilization of
  86.             the TPU file itself by the Windows Compiler.
  87.  
  88.             Since I  have a "real" job which requires my full attention,
  89.             and since  it doesn't  involve use  of these products in any
  90.             direct way,  I am  usually hard-pressed to find the personal
  91.             time to  conduct this  research.    Consequently,  I  always
  92.             refuse to  commit to follow-up or even error correction.  It
  93.             would  be  irresponsible  of  me  to  pretend  it  could  be
  94.             otherwise.  Even so, this is a revised report which contains
  95.             a few  error fixes  and discusses the newly enhanced program
  96.             which incorporates  these fixes  and  sports  some  enhanced
  97.             capabilities.
  98.  
  99.  
  100.  
  101.                                       Contents
  102.  
  103.  
  104.  
  105.            1. Introduction                                                5
  106.                1.1 Caveats                                                5
  107.                1.2 Evolution                                              6
  108.                1.3 Treatment                                              6
  109.            2. Gross File Structure                                        7
  110.                2.1 User Units                                             8
  111.                2.2 SYSTEM Unit                                            8
  112.            3. Locators                                                    8
  113.                3.1 Local Links                                            9
  114.                3.2 Global Links                                           9
  115.                3.3 Table Offsets                                          9
  116.                3.4 Basic Relationships                                   10
  117.            4. Unit Header                                                13
  118.                4.1 Description                                           13
  119.                4.2 UNIT Size                                             16
  120.            5. Symbol Dictionaries                                        16
  121.                5.1 Organization                                          16
  122.                5.2 Interface Dictionary                                  17
  123.                5.3 Debug Dictionary                                      17
  124.                5.4 Dictionary Elements                                   17
  125.                    5.4.1 Hash Tables                                     18
  126.                        5.4.1.1 Size                                      18
  127.                        5.4.1.2 Scope                                     19
  128.                        5.4.1.3 Special Cases                             19
  129.                    5.4.2 NAME ENTRIES                                    20
  130.                    5.4.3 NAME Stubs                                      20
  131.                        5.4.3.1 Label Declaratives ("O")                  20
  132.                        5.4.3.2 Un-Typed Constants ("P")                  21
  133.                        5.4.3.3 Named Types ("Q")                         21
  134.                        5.4.3.4 Variables, Fields, Typed Cons ("R")       22
  135.                        5.4.3.5 Subprograms & Methods ("S")               24
  136.                        5.4.3.6 Turbo Std Procedures ("T")                25
  137.                        5.4.3.7 Turbo Std Functions ("U")                 25
  138.                        5.4.3.8 Turbo Std "NEW" Routine ("V")             25
  139.                        5.4.3.9 Turbo Std Port Arrays ("W")               26
  140.                        5.4.3.10 Turbo Std External Variables ("X")       26
  141.                        5.4.3.11 Units ("Y")                              26
  142.                    5.4.4 Type Descriptors                                27
  143.                        5.4.4.1 Scope                                     27
  144.                        5.4.4.2 Prefix Part                               28
  145.                        5.4.4.3 Suffix Parts                              29
  146.                            5.4.4.3.1 Un-Typed                            29
  147.                            5.4.4.3.2 Structured Types                    29
  148.                                5.4.4.3.2.1 ARRAY Types                   30
  149.                                5.4.4.3.2.2 RECORD Types                  30
  150.                                5.4.4.3.2.3 OBJECT Types                  31
  151.                                5.4.4.3.2.4 FILE (non-TEXT) Types         31
  152.                                5.4.4.3.2.5 TEXT File Types               32
  153.                                5.4.4.3.2.6 SET Types                     32
  154.                                5.4.4.3.2.7 POINTER Types                 32
  155.                                5.4.4.3.2.8 STRING Types                  32
  156.                            5.4.4.3.3 Floating-Point Types                32
  157.                            5.4.4.3.4 Ordinal Types                       32
  158.                                5.4.4.3.4.1 "Integers"                    33
  159.  
  160.  
  161.                                        - iii -
  162.  
  163.  
  164.  
  165.                                       Contents
  166.  
  167.  
  168.                                5.4.4.3.4.2 BOOLEANs                      33
  169.                                5.4.4.3.4.3 CHARs                         33
  170.                                5.4.4.3.4.4 ENUMERATions                  34
  171.                            5.4.4.3.5 SUBPROGRAM Types                    34
  172.            6. Maps and Lists                                             35
  173.                6.1 PROC Map                                              35
  174.                6.2 CSeg Map                                              36
  175.                6.3 Typed CONST DSeg Map                                  37
  176.                6.4 Global VAR DSeg Map                                   37
  177.                6.5 DLL LIST                                              38
  178.                6.6 Donor Unit List                                       38
  179.                6.7 Source File List                                      39
  180.                6.8 DEBUG Trace Table                                     40
  181.            7. Code, Data, Fix-Up Info                                    40
  182.                7.1 Object CSegs                                          41
  183.                7.2 CONST DSegs                                           41
  184.                7.3 Fix-Up Data Tables                                    42
  185.            8. Supplied Program                                           45
  186.                8.1 TWU1                                                  45
  187.                    8.1.1 Unit TWU1EQU                                    46
  188.                    8.1.2 Unit TWU1RPT                                    46
  189.                    8.1.3 Unit TWU1UAM                                    46
  190.                    8.1.4 Unit TWU1UNA                                    47
  191.                8.2 Notes on Program Logic                                48
  192.                    8.2.1 Formatting the Dictionary                       48
  193.                    8.2.2 The Disassembler                                49
  194.            9. Unit Libraries                                             52
  195.                9.1 Library Structure                                     52
  196.            10. Inferences Drawn from Analyses                            53
  197.                10.1 Linker Granularity                                   53
  198.                10.2 Floating-Point Emulation                             53
  199.                    10.2.1 Version 6.0 Compiler For MS-DOS                54
  200.                    10.2.2 Version 1.0 Compiler For WINDOWS               54
  201.            11. Application Notes                                         55
  202.            12. Acknowledgements                                          56
  203.            13. References                                                57
  204.            14. INDEX                                                     58
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.                                        - iv -
  226.  
  227.  
  228.  
  229.                            Inside TURBO Pascal Unit Files            
  230.        ──────────────────────────────────────────────────────────────────────
  231.  
  232.  
  233.  
  234.        1. INTRODUCTION
  235.  
  236.  
  237.        This document  is  the  outcome  of  an  inquiry  conducted  into  the
  238.        structure and  content of  Borland Turbo  Pascal for  Windows (Version
  239.        1.0) Unit files.  This followed naturally from previous inquiries into
  240.        the structure  of Unit  Files for  versions 5.0-6.0 of Borland's Turbo
  241.        Pascal Compilers.   I  was further  stimulated to  undertake this as a
  242.        result of  a brief  conversation I had with the Principal Architect of
  243.        Turbo Pascal,  Mr. Anders  Hejlsberg, in Houston at the HAL-PC meeting
  244.        that served  as the  platform for  the formal  announcement  of  Turbo
  245.        Pascal for Windows.
  246.  
  247.  
  248.  
  249.        1.1 CAVEATS
  250.  
  251.  
  252.        The  material   contained   herein   represents   the   findings   and
  253.        interpretations of  the author.    A  great  deal  of  guess-work  was
  254.        required and  no assurances are given as to the accuracy of either the
  255.        findings of fact or the inferences contained herein which are the sole
  256.        work-product of  the author.   In  particular, only  the materials and
  257.        information that  any normal  Borland  customer  has  access  to  were
  258.        available to  the author.    Further,  no  Borland  source-codes  were
  259.        available as the Library Routine source is not licensed to the author.
  260.        In short,  there was  nothing irregular  about how these findings were
  261.        achieved.
  262.  
  263.        The material  contained herein  is placed in the public domain free of
  264.        copyright for  use of  the general public at its own risk.  The author
  265.        assumes no  liability for  any damages  arising from  the use  of this
  266.        material by  others.   If you make use of this information and you get
  267.        burned, TOUGH!   The  author accepts no obligation to correct any such
  268.        errors as  may exist  in the  supplied programs  or in the findings of
  269.        fact or opinion contained herein.
  270.  
  271.        On the  other hand, this is not a "complete" work in that a great many
  272.        questions remain open, especially as regards fine details.  The author
  273.        is highly-qualified  in neither  Intel 80xxx  Assembly Language nor in
  274.        Windows 3.0  application programming  and several open questions might
  275.        best be  addressed by  persons competent  in these  areas.  The author
  276.        welcomes the  input of interested readers who might be able to "flesh-
  277.        out" some  of these  open questions  with "hard"  answers so  that all
  278.        might benefit from their expertise.
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.        ──────────────────────────────────────────────────────────────────────
  289.        June 6, 1991                                                    Page 5
  290.  
  291.  
  292.  
  293.                            Inside TURBO Pascal Unit Files            
  294.        ──────────────────────────────────────────────────────────────────────
  295.  
  296.        1.2 EVOLUTION
  297.  
  298.  
  299.        The Unit first appeared in Turbo Pascal Version 4.0 (for MS-DOS) along
  300.        with the  ability to  create ".EXE"  instead of  ".COM" files.    This
  301.        author began  delving into these Unit files beginning with Version 5.0
  302.        of Turbo  Pascal and  each new version of the MS-DOS based product has
  303.        seen significant  changes in  both the  form and the content of ".TPU"
  304.        files.
  305.  
  306.        In contrast,  careful study  should make  it plain  that the Unit File
  307.        produced by  Turbo Pascal  for Windows  is remarkably  similar to that
  308.        produced by Turbo Pascal Version 6.0 (for MS-DOS).
  309.  
  310.        In the  main, the files produced by the MS-DOS product (TP6) were rich
  311.        with apparently useless fields within some of the data structures.  In
  312.        essence, the  Windows product  (TPW) has made use of these fields in a
  313.        coherent way  that makes  the Version  6 units appear to be subsets of
  314.        the Windows Units as far as format is concerned.
  315.  
  316.        The Windows  version development must have been well-advanced when the
  317.        DOS version  (6.0) hit the streets.  In fact, Mr. Anders Hejlsberg did
  318.        confirm my  speculation that the compiler "engine" used in the Windows
  319.        Product is the same as that used in version 6 of the DOS Product.
  320.  
  321.  
  322.  
  323.        1.3 TREATMENT
  324.  
  325.  
  326.        This report treats with BOTH Turbo Pascal for Windows and Turbo Pascal
  327.        Version 6.0 (for MS-DOS).   It views Unit Files for the MS-DOS version
  328.        as sub-sets  of those  for the  Windows version from the standpoint of
  329.        structure.   Because of  this, the supplied program is able to process
  330.        ".TPU" files from either compiler with little or no special handling.
  331.  
  332.        This doesn't  mean that Version 6.0 Units can be combined with Windows
  333.        Applications!  When an application (program) is built by either of the
  334.        compilers, ALL  units must have been compiled by that same compiler if
  335.        for no  other reason  than that  the SYSTEM Unit (for one) is uniquely
  336.        tailored to each of these environments.
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.        ──────────────────────────────────────────────────────────────────────
  353.        June 6, 1991                                                    Page 6
  354.  
  355.  
  356.  
  357.                            Inside TURBO Pascal Unit Files            
  358.        ──────────────────────────────────────────────────────────────────────
  359.  
  360.        2. GROSS FILE STRUCTURE
  361.  
  362.  
  363.        A Turbo  Pascal Unit  file consists  of an array of bytes that is some
  364.        exact multiple  of sixteen  (16).   "Signature" information allows the
  365.        compiler to  verify that  the .TPU  file was compiled with the correct
  366.        compiler version  and to  verify that the file is of the correct size.
  367.        The fine  structure of the file will be addressed in later sections at
  368.        ever increasing levels of detail.
  369.  
  370.        Graphically, the  file may be regarded as having the following general
  371.        layout (major sections bounded by ═ )
  372.  
  373.              ╔═══════════════════╗
  374.              ║ Unit Header       ║        Main Index to Unit File
  375.              ╟───────────────────╢
  376.              ║ Dictionaries:     ║
  377.              ║   a) Interface    ║
  378.              ║   b) Debug      * ║        For Local Symbol Access
  379.              ╟───────────────────╢
  380.              ║ PROC Map          ║
  381.              ╟───────────────────╢
  382.              ║ CSeg Map        * ║        May be Empty
  383.              ╟───────────────────╢
  384.              ║ CONST DSeg Map  * ║        May be Empty
  385.              ╟───────────────────╢
  386.              ║ VAR DSeg Map    * ║        May be Empty
  387.              ╟───────────────────╢
  388.              ║ DLL List        * ║        May be Empty
  389.              ╟───────────────────╢
  390.              ║ Donor Units     * ║        May be Empty
  391.              ╟───────────────────╢
  392.              ║ Source Files      ║
  393.              ╟───────────────────╢
  394.              ║ Trace Table     * ║        May be Empty
  395.              ╠═══════════════════╣
  396.              ║ CODE Group      * ║        May be Empty
  397.              ╠═══════════════════╣
  398.              ║ DATA Group      * ║        May be Empty
  399.              ╠═══════════════════╣
  400.              ║ Code Fix-Ups    * ║        May be Empty
  401.              ╠═══════════════════╣
  402.              ║ Data Fix-Ups    * ║        May be Empty
  403.              ╚═══════════════════╝
  404.  
  405.  
  406.        Each of  the sections  outlined by double lines is capable of being up
  407.        to 64K  bytes long.   The  Dictionary Area begins with the Unit Header
  408.        and continues through the Trace Table.
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.        ──────────────────────────────────────────────────────────────────────
  417.        June 6, 1991                                                    Page 7
  418.  
  419.  
  420.  
  421.                            Inside TURBO Pascal Unit Files            
  422.        ──────────────────────────────────────────────────────────────────────
  423.  
  424.        2.1 USER UNITS
  425.  
  426.  
  427.        Units  compiled   by  ordinary  users  have  a  very  straight-forward
  428.        appearance and  content.   The SYSTEM.TPU  file is quite another thing
  429.        however.
  430.  
  431.  
  432.  
  433.        2.2 SYSTEM UNIT
  434.  
  435.  
  436.        The SYSTEM.TPU  file (found  in TURBO.TPL  and in the TPW.TPL file) is
  437.        unique in several respects.  It contains several types of entries that
  438.        just  don't   seem  to  be  achievable  by  ordinary  users,  and  the
  439.        arrangement of the entries in the dictionary is unique.  Normally, the
  440.        Name Entry for the Unit immediately follows the hash table but, in the
  441.        "SYSTEM" unit,  this is  not true.  Rather, the hash table is followed
  442.        by all the descriptors for the built-in types, followed by descriptors
  443.        for the  standard procedures and functions, followed by the Name Entry
  444.        for  the   Unit,  followed  by  the  conventional  dictionary  entries
  445.        achievable by  normal PASCAL  coding such  as the  Typed Constants and
  446.        Variables defined in the "SYSTEM" unit.
  447.  
  448.        Try to  compile a  Unit named  "SYSTEM" and you find that the compiler
  449.        wants a  file called  "SYSTEM.TPS".   I suspect that "SYSTEM.TPS" is a
  450.        file that  contains a  pre-initialized interface  hash table  plus the
  451.        descriptors for  the standard types and the descriptors for the built-
  452.        in procedures  and functions  stored in the "SYSTEM" Unit (which would
  453.        otherwise require special syntax to define).
  454.  
  455.        The compiler  can't operate  normally without  a "SYSTEM" unit so this
  456.        file probably  provides  a  "bootstrap"  mechanism  for  the  built-in
  457.        descriptors needed to build "SYSTEM.TPU".
  458.  
  459.  
  460.  
  461.        3. LOCATORS
  462.  
  463.  
  464.        The data  in these  files has  need of  structure and  organization to
  465.        support efficient access by the various programs such as the compiler,
  466.        the linker  and the  debugger.   This organization is built on a solid
  467.        foundation of locators employed in the unit's data structures.
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.        ──────────────────────────────────────────────────────────────────────
  481.        June 6, 1991                                                    Page 8
  482.  
  483.  
  484.  
  485.                            Inside TURBO Pascal Unit Files            
  486.        ──────────────────────────────────────────────────────────────────────
  487.  
  488.        3.1 LOCAL LINKS
  489.  
  490.  
  491.        Local Links  (LL's) are  items of type WORD (2 bytes) which contain an
  492.        offset which  is relative  to the origin of the Dictionary Area of the
  493.        unit.   This implies  that the  Dictionary Area  must be somewhat less
  494.        than 64K  bytes in  size.   If the  Dictionary Area is loaded into the
  495.        heap, then  an LL  can be  used to  locate any  byte in the Dictionary
  496.        Area.  (See Below)
  497.  
  498.              Type LL  = Word; { Local Scope Locators }
  499.  
  500.  
  501.  
  502.        3.2 GLOBAL LINKS
  503.  
  504.  
  505.        Global Links  (LG's) are used to locate type descriptors and to locate
  506.        allocation data  for variables  with the  ABSOLUTE attribute which may
  507.        reside in  other Units  (i.e., units  external to  the present  unit).
  508.        LG's are structured items consisting of two (2) words (see below).
  509.  
  510.             LG  = RECORD
  511.                  UntLL: LL; { To item in Unit Named by LL below    }
  512.                  UntId: LL; { Stub Type "Y" Name Entry in our Unit }
  513.             END;
  514.  
  515.        The first  of these  is an  LL that  is relative  to the origin of the
  516.        Dictionary Area  of the (possibly external) unit.  It locates either a
  517.        Type Descriptor  or the  stub of  the  Name  entry  which  establishes
  518.        storage allocation.   The  second word is an LL which locates the stub
  519.        of the  Name entry  in the  current unit  dictionary for the (possibly
  520.        external) target  unit.   The Name entry for this stub identifies name
  521.        of the unit that contains the item the LG points to.
  522.  
  523.        This provides  a handy  mechanism for  locating type  descriptors  and
  524.        allocation information  which  may  be  defined  in  other  separately
  525.        compiled units.
  526.  
  527.  
  528.  
  529.        3.3 TABLE OFFSETS
  530.  
  531.  
  532.        Finally, various  data-structures within  a .TPU file are organized as
  533.        arrays of fixed-length records or as lists of variable-length records.
  534.        Efficient access  to such  records is  achieved by  means  of  offsets
  535.        rather than subscripts (an addressing technique denied Pascal).  These
  536.        offsets are  relative to  the  origin  of  the  array  or  list  being
  537.        referenced.
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.        ──────────────────────────────────────────────────────────────────────
  545.        June 6, 1991                                                    Page 9
  546.  
  547.  
  548.  
  549.                            Inside TURBO Pascal Unit Files            
  550.        ──────────────────────────────────────────────────────────────────────
  551.  
  552.        3.4 BASIC RELATIONSHIPS
  553.  
  554.  
  555.           ╔═══>            ┌────────────────┐        ┌──────────────────────┐
  556.           ║      ┌────────<┤  Unit Header   │        │ Symbol Dictionary    │
  557.           ║ D    │         └────────────────┘        │ (names, types etc)   │
  558.           ║ I    │   LL    ┌────────────────┐  LL's  │ defined in INTERFACE │
  559.           ║ C    ├────────>┤ INTERFACE Hash ├───────>┤                      │
  560.           ║ T    │         └────────────────┘        └──────────┬───────────┘
  561.           ║ I    │   LL    ┌────────────────┐  LL's  ┌──────────┴───────────┐
  562.           ║ O    ├────────>│   DEBUG Hash   ├───────>┤   DEBUG Dictionary   │
  563.           ║ N    │         └────────────────┘        │ Local Symbol option  │
  564.           ║ A    │   LL    ┌────────────────┐        │ builds this.  Holds  │
  565.           ║ R    ├────────>┤ PROC Map Table │        │ names and types etc  │
  566.           ║ Y    │         └────────────────┘        │ from IMPLEMENTATION  │
  567.           ║      │   LL    ┌────────────────┐        │ Linked to INTERFACE  │
  568.           ║ A    ├────────>┤ CSeg Map Table │?       │ part by LL's.        │
  569.           ║ R    │         └────────────────┘        │                      │
  570.           ║ E    │   LL    ┌────────────────┐        └──────────────────────┘
  571.           ║ A    ├────────>┤ DSeg Map CONST │?
  572.           ║      │         └────────────────┘
  573.           ║      │   LL    ┌────────────────┐
  574.           ║      ├────────>┤ DSeg Map VAR's │?
  575.           ║      │         └────────────────┘
  576.           ║      │   LL    ┌────────────────┐
  577.           ║      ├────────>│ DLL List       │?
  578.           ║      │         └────────────────┘             IMPORTANT NOTES
  579.           ║      │   LL    ┌────────────────┐         ──────────────────────
  580.           ║      ├────────>┤ Donor Unit List│?        Some of the structures
  581.           ║      │         └────────────────┘         shown in this figure
  582.           ║      │   LL    ┌──────────────────┐       are built only if they
  583.           ║      ├────────>┤ Source File List │       are needed.  These are
  584.           ║      │         └──────────────────┘       marked by a "?" next
  585.           ║      │   LL    ┌──────────────────┐       to the box.
  586.           ║      ├────────>┤ Debug Step Ctls  │?
  587.           ╚═══>  │         └──────────────────┘       If the DEBUG Dictionary
  588.                  │   **    ┌───────────────┐          is missing, its LL
  589.                  ├────────>┤ CODE Segments │?         leads directly to the
  590.                  │         └───────────────┘          INTERFACE Dictionary.
  591.                  │   **    ┌─────────────────┐        ──────────────────────
  592.                  ├────────>┤ CONST DATA Segs │?
  593.                  │         └─────────────────┘
  594.                  │   **    ┌────────────────┐
  595.                  ├────────>┤ CODE Fix-Ups   │?
  596.                  │         └────────────────┘
  597.                  │   **    ┌────────────────┐
  598.                  └────────>┤ CONST Fix-Ups  │?
  599.                            └────────────────┘
  600.  
  601.        This figure  illustrates the role of the Unit Header in tying together
  602.        the various  data structures  in the  Unit.  The type of link is shown
  603.        next to a flow-line by "LL", "LG" or "**".  "LL" and "LG" are explicit
  604.        pointers while  "**" shows  a locator  whose value  is computed  using
  605.        other data in the Unit Header and that no explicit pointer exists.
  606.  
  607.  
  608.        ──────────────────────────────────────────────────────────────────────
  609.        June 6, 1991                                                   Page 10
  610.  
  611.  
  612.  
  613.                            Inside TURBO Pascal Unit Files            
  614.        ──────────────────────────────────────────────────────────────────────
  615.  
  616.  
  617.         ┌────(from hash tables,other Name Entries)
  618.         │
  619.         │    ┌─────────────┬──────────────────────────────────┐
  620.         │    │ Header Part │ Stub Part -- many formats        │
  621.         └───>┤ - - - - - - │ - - - ┌───────────────────────── │
  622.              │             │ data, │ Some stubs have embedded │   Name
  623.              │ Name, Class │ links │ Type Descriptors         │   Entry
  624.              │ and link to │ (see  │     ┌─────────────────── │
  625.              │ prior entry │ below)│     │ INLINE Declarative │
  626.              │ having same │   *   │     │ code bytes for a   │
  627.              │ hash-if any │   │   │     │ "macro" type PROC  │
  628.              └─────────────┴───│──────────────────────────────┘
  629.                     ┌──────────┘
  630.                     │
  631.                     │ FAR pntr   ┌────────────────────────────┐
  632.                     ├───────────>┤ Absolute Memory Locations  │
  633.                     │            └────────────────────────────┘
  634.                     │            ┌─────────────────────────────┐
  635.                     │   LG's     │ Type Descriptors and stubs  │
  636.                     ├───────────>┤ of Dictionary Entries used  │
  637.                     │            │ for absolute equivalences   │
  638.                     │            └─────────────────────────────┘
  639.                     │            ┌─────────────────────────────────┐
  640.                     │   LL's     │ Nested Scope Hash Tables        │
  641.                     ├───────────>┤ Parent Scope Dictionary Entries │
  642.                     │            │ Record Fields                   │
  643.                     │            │ Object Fields/Methods           │
  644.                     │            └─────────────────────────────────┘
  645.                     │            ┌──────────────────────┐
  646.                     │ Offsets    │ CONST DSeg Map Table │
  647.                     └───────────>┤ PROC Map Table       │
  648.                                  │ VAR DSeg Map Table   │
  649.                                  └──────────────────────┘
  650.  
  651.  
  652.  
  653.        This figure illustrates the many types of entities that associate with
  654.        Name Entries  and particularly  with their Stub Parts.  Not all of the
  655.        links shown occur in a single Stub format, but all of the links in the
  656.        figure can  and do  exist in  selected cases.   The purpose here is to
  657.        show the  flexibility of  the system  of links in associating required
  658.        data with the Name Entry and its identifying symbol.
  659.  
  660.        While it may not be apparent from the figure, the dictionary structure
  661.        as a whole may be viewed as a cyclic directed graph which is rooted in
  662.        the DEBUG  Hash Table.  The recursive properties exhibited by the node
  663.        relationships permit direct support of the scope rules of Turbo Pascal
  664.        with simplicity and elegance.  As one might expect, the representation
  665.        of the  required information  lends itself to efficient use of storage
  666.        since the  representations are compact and there is very little in the
  667.        way of  redundancy.  The small amount of redundancy that does exist is
  668.        apparently aimed at speeding access to certain structures by the Turbo
  669.        components (compiler, linker and debugger).
  670.  
  671.  
  672.        ──────────────────────────────────────────────────────────────────────
  673.        June 6, 1991                                                   Page 11
  674.  
  675.  
  676.  
  677.                            Inside TURBO Pascal Unit Files            
  678.        ──────────────────────────────────────────────────────────────────────
  679.  
  680.  
  681.         ┌────(implied links, explicit LG's from other structures)
  682.         │
  683.         │    ┌─────────────────────────────────────────────┐
  684.         │    │ Flags and codes, allocation widths for data │  Type
  685.         └───>┤ and VMT's, subrange constraints, formal     │  Descriptor
  686.              │ parameter descriptors, implicit associated  │  Contents &
  687.              │ type descriptors, LL's, LG's and Offsets.   │  Linkages
  688.              └──────┬──────────────────────────────────────┘
  689.                     │
  690.                     │
  691.                     │    LG's       ┌──────────────────┐
  692.                     ├──────────────>┤ Type Descriptors │
  693.                     │               └──────────────────┘
  694.                     │
  695.                     │               ┌───────────────────────────────┐
  696.                     │    LL's       │ Method Name Entries           │
  697.                     ├──────────────>┤ Nested Scope Hash Tables      │
  698.                     │               │ Nested Scope Field Chains     │
  699.                     │               │ Parent Scope Name Entry       │
  700.                     │               └───────────────────────────────┘
  701.                     │
  702.                     │  Offsets      ┌──────────────────────────────────┐
  703.                     └──────────────>┤ VMT pointers in Object Instances │
  704.                                     │ CONST DSeg Map Table Entries     │
  705.                                     └──────────────────────────────────┘
  706.  
  707.  
  708.        This figure illustrates the relationships between Type Descriptors and
  709.        other structures in the dictionary.  Not all the links shown can exist
  710.        with a single Type Descriptor since there are several variant forms of
  711.        these descriptors  (depending on  base type) but in combination, these
  712.        linkages are  feasible.   In addition to links, a great amount of data
  713.        is stored  which is peculiar to a given type declaration.  Descriptors
  714.        can be  -- and are -- shared.  Indeed, they were designed with that in
  715.        mind.   Once a  NAMED type is declared, all entities that reference it
  716.        are linked to it in some way (usually by an LG).
  717.  
  718.        Almost every  form of  type descriptor is found in the SYSTEM unit and
  719.        this fact is used to advantage.  When un-typed constants are declared,
  720.        a built-in  type descriptor  is referenced  (via an LG) which provides
  721.        necessary information for maintenance of orderly dictionary structure.
  722.        When a  named-type is declared, it is almost always decomposed into an
  723.        expression based on the built-in types of Turbo Pascal which are found
  724.        in the SYSTEM unit with the aid of an LG.
  725.  
  726.        The semantics  underlying the  idea of  the  Unit  mandate  this  very
  727.        approach since  program modules  of any class which make references to
  728.        units for  definitions use  the definitions as implemented by the unit
  729.        which contains them.  Re-defining the unit or any of its defined types
  730.        leads to  a natural  requirement to  re-compile those  program modules
  731.        which rely  on the  unit for  definitions.   The impact is fundamental
  732.        since the  storage representation  of a  unit-defined named  type  can
  733.        change in quite radical ways.
  734.  
  735.  
  736.        ──────────────────────────────────────────────────────────────────────
  737.        June 6, 1991                                                   Page 12
  738.  
  739.  
  740.  
  741.                            Inside TURBO Pascal Unit Files            
  742.        ──────────────────────────────────────────────────────────────────────
  743.  
  744.        4. UNIT HEADER
  745.  
  746.  
  747.        The Unit  Header comprises  the first  64 bytes  of the .TPU file.  It
  748.        contains LL's  that effectively  locate all other sections of the .TPU
  749.        file plus  statistics  that  enable  a  little  cross-checking  to  be
  750.        performed.   Some parts  of the  Unit Header appear to be reserved for
  751.        future use  since no  unit examined  by this author has ever contained
  752.        non-zero data in these apparently reserved fields.
  753.  
  754.  
  755.  
  756.        4.1 DESCRIPTION
  757.  
  758.  
  759.        The Unit Header provides a high-level locator table whereby each major
  760.        structure in the unit file can be addressed.  The following provides a
  761.        Pascal-like explanation  of the  layout  of  the  header  followed  by
  762.        further narrative  discussion of the contents of the individual fields
  763.        in the Unit Header.
  764.  
  765.              Type HdrAry = Array[0..3] of Char;
  766.  
  767.              UnitHeader = Record
  768.  
  769.               UHEYE : HdrAry;   { +00 : = 'TPU9'                      }
  770.               UHxxx : HdrAry;   { +04 : = $00000000                   }
  771.               UHUDH : LL;       { +08 : to Name Entry for This Unit   }
  772.               UGIHT : LL;       { +0A : to Hash Table (INTERFACE)     }
  773.               UHPMT : LL;       { +0C : to PROC Map                   }
  774.               UHCMT : LL;       { +0E : to CSeg Map                   }
  775.               UHTMT : LL;       { +10 : to DSeg Map-Typed CONST's     }
  776.               UHDMT : LL;       { +12 : to DSeg Map-GLOBAL Variables  }
  777.               UHDLL : LL;       { +14 : to DLL List (Windows Only)    }
  778.               UHLDU : LL;       { +16 : to Donor Unit List            }
  779.               UHLSF : LL;       { +18 : to Source file List           }
  780.               UHDBT : LL;       { +1A : to Debug Trace Step Controls  }
  781.               UHENC : LL;       { +1C : Size of Dictionary Area       }
  782.               UHZCS : Word;     { +1E : Size of CODE Group            }
  783.               UHZDT : Word;     { +20 : Size of Typed CONST Group     }
  784.               UHZFA : Word;     { +22 : Fix-Up Bytes (CODE Group)     }
  785.               UHZFT : Word;     { +24 : Fix-Up Bytes (Typed CONST's)  }
  786.               UHZFV : Word;     { +26 : Size of GLOBAL VAR Data       }
  787.               UHDHT : LL;       { +28 : to Hash Table (DEBUG)         }
  788.               UHSOV : Word;     { +2A : Flags - Mostly Unknown        }
  789.               UHPad : Array[0..9]
  790.                       of Word;  { +2C : Reserved for Future Expansion }
  791.  
  792.              End; { UnitHeader }
  793.  
  794.          UHEYE   contains the  characters "TPU9"  in that  order.   This is
  795.                  clear evidence that this unit was compiled by Turbo Pascal
  796.                  Version 6.0 or by Turbo Pascal for Windows Version 1.0.
  797.  
  798.          UHxxx   is apparently reserved and contains binary zeros.
  799.  
  800.        ──────────────────────────────────────────────────────────────────────
  801.        June 6, 1991                                                   Page 13
  802.  
  803.  
  804.  
  805.                            Inside TURBO Pascal Unit Files            
  806.        ──────────────────────────────────────────────────────────────────────
  807.  
  808.          UHUDH   contains an  LL (WORD)  which points  to the Name Entry in
  809.                  which the name of this unit is found.
  810.  
  811.          UHIHT   contains an LL (WORD) which points to a Hash table that is
  812.                  the root of the Interface Dictionary graph.
  813.  
  814.          UHPMT   contains an  LL (WORD)  which points  to the  PROC Map for
  815.                  this unit.   The  PROC Map  contains  an  entry  for  each
  816.                  Procedure or  Function declared  in the  unit (except  for
  817.                  INLINE types),  plus an  entry for the Unit Initialization
  818.                  section.   The length  of  the  PROC  Map  (in  bytes)  is
  819.                  determined by subtracting this UHPMT from UHCMT.
  820.  
  821.          UHCMT   contains an  LL (WORD)  which points  to  the  CSeg  (CODE
  822.                  Group) Map  for this unit.  The CSeg Map contains an entry
  823.                  for each  CODE Segment  produced by  the compiler  plus an
  824.                  entry for  each of  the CODE Segments included via the {$L
  825.                  filename.OBJ} compiler  directive.  The length of this Map
  826.                  (in bytes)  is obtained  by subtracting  UNCMT from UHTMT.
  827.                  The result  may be  zero in  which case  the CSeg  Map  is
  828.                  empty.
  829.  
  830.          UHTMT   contains an  LL (WORD)  which points  to  the  DSeg  (DATA
  831.                  Segment) Map  that maps  the initializing  data for  Typed
  832.                  CONST items  plus  templates  for  VMT's  (Virtual  Method
  833.                  Tables) and DMT's (Windows Dynamic Method Tables) that are
  834.                  associated with OBJECTS which employ Virtual Methods.  The
  835.                  length of  this Map  (in bytes) is obtained by subtracting
  836.                  UHTMT from  UHDMT.   The result  may be zero in which case
  837.                  this DSeg Map is empty.
  838.  
  839.          UHDMT   contains an  LL (WORD)  which points  to  the  DSeg  (DATA
  840.                  Segment) Map  that contains  the specifications  for  DSeg
  841.                  storage required  by VARiables whose scope is GLOBAL.  The
  842.                  length of  this Map  (in bytes) is obtained by subtracting
  843.                  UHDMT from  UHDLL.   The result  may be zero in which case
  844.                  this DSeg Map is empty.
  845.  
  846.          UHDLL   contains an  LL (WORD)  which points  to the  DLL list  in
  847.                  Windows.  In Version 6.0, this is always zero.
  848.  
  849.          UHLDU   contains an  LL (WORD)  which points  to a  table of units
  850.                  which contribute  either CODE or DATA Segments to the .EXE
  851.                  file for  a program  using this  Unit.  This is called the
  852.                  "Donor Unit  Table".   The length of this table (in bytes)
  853.                  is obtained by subtracting UHLDU from the word UHLSF.  The
  854.                  result may be zero in which case this table is empty.
  855.  
  856.          UHLSF   contains an  LL (WORD)  which points to a list of "source"
  857.                  files.   These  are  the  files  used  as  sources  during
  858.                  compilation.   Examples are the Pascal Source for the Unit
  859.                  itself,  plus   the  .OBJ   files  linked   via  the   {$L
  860.                  filename.OBJ} compiler directive.  The length of this list
  861.                  (in bytes)  is obtained by subtracting UHLSF from the word
  862.                  UHDBT.  There should be at least one entry in this list.
  863.  
  864.        ──────────────────────────────────────────────────────────────────────
  865.        June 6, 1991                                                   Page 14
  866.  
  867.  
  868.  
  869.                            Inside TURBO Pascal Unit Files            
  870.        ──────────────────────────────────────────────────────────────────────
  871.  
  872.          UHDBT   contains an  LL (WORD)  which points to a Trace Table used
  873.                  by the  DEBUGGER for  "stepping"  through  a  Function  or
  874.                  Procedure contained  in this  Unit.   The length  of  this
  875.                  table (in bytes) is obtained by subtracting UHDBT from the
  876.                  word UHENC.   The  result may  be zero  in which case this
  877.                  table is empty.
  878.  
  879.          UHZDA   is a  WORD that  contains the  total  byte  count  of  the
  880.                  Dictionary Area  for this  unit.   All  bytes  up  to  and
  881.                  including the Trace Table are included in this count.
  882.  
  883.          UHZCS   is a  WORD that  contains the total byte count of all CODE
  884.                  Segments compiled into this Unit.
  885.  
  886.          UHZDT   is a  WORD that contains the total byte count of all Typed
  887.                  CONST, DMT and VMT DATA Segments compiled into this unit.
  888.  
  889.          UHZFA   is a WORD that contains the total byte count of the Fix-Up
  890.                  Data Table for this unit for CODE (CSegs).
  891.  
  892.          UHZFT   is a WORD that contains the total byte count of the Fix-Up
  893.                  Data Table for Typed CONST's.  This usually implies that a
  894.                  VMT or DMT is getting its pointers relocated.
  895.  
  896.          UHZFV   is a WORD that contains the total byte count of all GLOBAL
  897.                  VAR DATA Segments compiled into this unit.
  898.  
  899.          UHDHT   contains an  LL (WORD)  which points to a Hash Table which
  900.                  is the  root of the DEBUGGER Dictionary.  If Local Symbols
  901.                  were generated  by the compiler (directive {$L+}) then ALL
  902.                  symbols declared  in the  unit can  be accessed  from this
  903.                  Hash Table.   If Local Symbols were suppressed there is no
  904.                  such Dictionary  and the  LL stored  here  points  to  the
  905.                  INTERFACE Dictionary.
  906.  
  907.          UHSOV   This word contains flags.  I have only been able to expose
  908.                  a few of the values with any real confidence.  Here's what
  909.                  I know so far (expressed by bit numbers 15..0):
  910.  
  911.                  15..13:   always zero?
  912.                  12:       always zero for Version 6.0 (DOS) Compiler?
  913.                            1=DISCARDABLE, 0=PERMANENT Windows Segment.
  914.                  11..7:    always zero?
  915.                  6:        always zero for Version 6.0 (DOS) Compiler?
  916.                            1=PRELOAD, 0=DEMANDLOAD Windows Segment.
  917.                  5:        always zero?
  918.                  4:        always zero for Version 6.0 (DOS) Compiler?
  919.                            1=MOVEABLE, 0=FIXED Windows Segment.
  920.                  3:        always zero?
  921.                  2:        0=DOS Compiler, 1=WINDOWS Compiler?
  922.                  1:        1=DOS Compiler with {$O+}, else zero?
  923.                  0:        Unclear.  Seems to imply that either this unit,
  924.                            or one that it references requires emulation
  925.                            support but this is only a guess.
  926.  
  927.  
  928.        ──────────────────────────────────────────────────────────────────────
  929.        June 6, 1991                                                   Page 15
  930.  
  931.  
  932.  
  933.                            Inside TURBO Pascal Unit Files            
  934.        ──────────────────────────────────────────────────────────────────────
  935.  
  936.          UHPad   begins a  series of  ten (10)  words that  are  apparently
  937.                  reserved for future use.  Nothing but zeros have ever been
  938.                  seen here by this author.
  939.  
  940.  
  941.  
  942.        4.2 UNIT SIZE
  943.  
  944.  
  945.        An independent  check on  the size of the .TPU file is available using
  946.        information contained  in the Unit Header.  This is also important for
  947.        .TPL (Unit Library) organization.  To compute the file :size, refer to
  948.        the five  (5) words  -- UHZDA,  UHZCS, UHZDT, UHZFA, and UHZFT.  Round
  949.        the contents  of each of these words to the lowest multiple of 16 that
  950.        is greater  than or  equal to the content of that word.  Then form the
  951.        sum of  the rounded  words.   This is the .TPU file size in bytes -- a
  952.        LongInt result.
  953.  
  954.        A Unit MAY be larger than 64K bytes.  I finally tumbled to this when I
  955.        began to analyze the Windows Unit "WOBJECTS".  I now feel that each of
  956.        the sections  referenced by  the sizes  above may  be up  to 64K bytes
  957.        long.  This implies an upper limit for unit size of around 320K bytes.
  958.        My face is actually quite red over this.  Since a Unit has always been
  959.        capable of  producing a 64K Code Segment not to mention a Data Segment
  960.        of nearly the same size, I can't explain why the significance of these
  961.        "size" words didn't dawn on me sooner.
  962.  
  963.  
  964.  
  965.        5. SYMBOL DICTIONARIES
  966.  
  967.  
  968.        This area contains all available documentation of declared symbols and
  969.        procedure blocks  defined within  the unit.    Depending  on  compiler
  970.        options in  effect when  the unit  was  compiled,  this  section  will
  971.        contain at  a minimum,  the INTERFACE  declarations, and at a maximum,
  972.        ALL declarations.   The information stored in the dictionary is highly
  973.        dependent on  the context  of the  symbol declared.   We defer further
  974.        explanation to the appropriate section which follows.
  975.  
  976.  
  977.  
  978.        5.1 ORGANIZATION
  979.  
  980.  
  981.        A dictionary  is organized  with a  Hash Table  as its root.  The hash
  982.        table is used to provide rapid access to identifiers.
  983.  
  984.        A dictionary  may be thought of as a directed graph.  Each subgraph is
  985.        rooted in  a hash  table.   There may be a great many hash tables in a
  986.        given unit  and their number depends on unit complexity as well as the
  987.        options chosen when the unit was compiled.  Use of the {$L+} directive
  988.        produces the  largest dictionaries.   The hash tables are explained in
  989.        detail a few sections further on.
  990.  
  991.  
  992.        ──────────────────────────────────────────────────────────────────────
  993.        June 6, 1991                                                   Page 16
  994.  
  995.  
  996.  
  997.                            Inside TURBO Pascal Unit Files            
  998.        ──────────────────────────────────────────────────────────────────────
  999.  
  1000.        Hash tables  point to  Name Entries.  When two or more symbols produce
  1001.        the same  hash function  result,  a  "collision"  is  said  to  occur.
  1002.        Collisions  are  resolved  by  the  time-honored  method  of  chaining
  1003.        together the  Name Entries  of those  symbols  having  the  same  hash
  1004.        function result.   Dictionary supersetting is accomplished using these
  1005.        chains.
  1006.  
  1007.  
  1008.  
  1009.        5.2 INTERFACE DICTIONARY
  1010.  
  1011.  
  1012.        The INTERFACE  dictionary  contains  all  symbols  and  the  necessary
  1013.        explanatory data  for the  INTERFACE section  of a  Unit.  Symbols get
  1014.        added to  the  Unit  using  increasing  storage  addresses  until  the
  1015.        IMPLEMENTATION section is encountered.
  1016.  
  1017.  
  1018.  
  1019.        5.3 DEBUG DICTIONARY
  1020.  
  1021.  
  1022.        The Debug  dictionary (if  present) is  a superset  of  the  INTERFACE
  1023.        dictionary.   It is  used by  the Turbo  Debugger to  support its many
  1024.        features when  tracing through a unit.  If present, this dictionary is
  1025.        rooted in  its  own  hash  table.    The  hash  table  is  effectively
  1026.        initialized when  the  IMPLEMENTATION  keyword  is  processed  by  the
  1027.        compiler.   This takes  the form  (initially) of an unmodified copy of
  1028.        the INTERFACE  hash table,  to which  symbols are  added in  the usual
  1029.        fashion.   Thus, the  hash chains constructed or extended at this time
  1030.        lead naturally to the INTERFACE chains and this is how the superset is
  1031.        effectively implemented.
  1032.  
  1033.  
  1034.  
  1035.        5.4 DICTIONARY ELEMENTS
  1036.  
  1037.  
  1038.        The dictionary contains four major elements.  These are:  hash tables,
  1039.        Name Entries,  Name Stubs  and  Type  Descriptors.    The  distinction
  1040.        between Name  Entries  and  Name  Stubs  might  appear  to  be  rather
  1041.        arbitrary.   They might just as easily be regarded as a single element
  1042.        (such as  symbol entry).   However,  the case  for the separate entity
  1043.        approach is  strong since Stubs are DIRECTLY addressed via LG's and --
  1044.        more to  the point  -- ONLY  by LG's.   Thus, it seems reasonable that
  1045.        this is  a separate  and very  important structure  -- at least in the
  1046.        minds of the architects at Borland.
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.  
  1053.  
  1054.  
  1055.  
  1056.        ──────────────────────────────────────────────────────────────────────
  1057.        June 6, 1991                                                   Page 17
  1058.  
  1059.  
  1060.  
  1061.                            Inside TURBO Pascal Unit Files            
  1062.        ──────────────────────────────────────────────────────────────────────
  1063.  
  1064.        5.4.1 HASH TABLES
  1065.  
  1066.  
  1067.        As has  been intimated,  Hash Tables  are  the  glue  that  binds  the
  1068.        dictionary entries  together and  gives the  dictionary  its  "shape".
  1069.        They effectively  implement the  scope rules of the language and speed
  1070.        access to essential information.
  1071.  
  1072.        Each Hash table begins with a 2-byte size descriptor.  This descriptor
  1073.        contains the  number of bytes in the table proper (less 2).  Thus, the
  1074.        descriptor directly  points to the last bucket in the hash table.  For
  1075.        a hash  table of  128 bytes,  the size  descriptor contains  126.  The
  1076.        first bucket in the table immediately follows the size descriptor.
  1077.  
  1078.  
  1079.  
  1080.        5.4.1.1 SIZE
  1081.  
  1082.  
  1083.        So far,  three different  hash table  sizes have  been observed.   The
  1084.        INTERFACE and  DEBUG hash tables are usually 128 bytes (64 entries) in
  1085.        size plus  2 bytes  of size  description, but the SYSTEM.TPU unit is a
  1086.        special case,  containing only  16 entries.   Hash tables which anchor
  1087.        subgraphs whose  scope is  relatively local  usually contain  four (4)
  1088.        entries (8 bytes).
  1089.  
  1090.        Graphically, a Hash Table with four slots has the following layout:
  1091.  
  1092.              ┌────────────────────┐
  1093.              │       0006h        │      Size Descriptor
  1094.              ├════════════════════┤
  1095.              │       slot 0       │      an LL or zero
  1096.              ├────────────────────┤
  1097.              │       slot 1       │      an LL or zero
  1098.              ├────────────────────┤
  1099.              │       slot 2       │      an LL or zero
  1100.              ├────────────────────┤
  1101.              │       slot 3       │      an LL or zero
  1102.              └────────────────────┘
  1103.  
  1104.        It should  be noted  that the Size Descriptor furnishes an upper bound
  1105.        for the  hash function  itself.  Thus, it seems possible that a single
  1106.        hash function is used for all hash tables and that its result is ANDed
  1107.        with the  Size Descriptor  to get the final result.  Because the sizes
  1108.        are chosen  as they  are (powers of 2) this is feasible.  Note that in
  1109.        the above  example, 6  = 2 * (n - 1) where n = 4 {slot count}.  All of
  1110.        the hash tables observed so far have this property.
  1111.  
  1112.        One final  note on this subject.  Given these properties, "Folding" of
  1113.        sparse hash  tables is  a rather  trivial exercise  so long as the new
  1114.        hash table also contains a number of slots that is a power of 2.  This
  1115.        point is  intriguing when  one recalls  that the System.TPU hash table
  1116.        has only 16 slots rather than the usual 64.
  1117.  
  1118.  
  1119.  
  1120.        ──────────────────────────────────────────────────────────────────────
  1121.        June 6, 1991                                                   Page 18
  1122.  
  1123.  
  1124.  
  1125.                            Inside TURBO Pascal Unit Files            
  1126.        ──────────────────────────────────────────────────────────────────────
  1127.  
  1128.        5.4.1.2 SCOPE
  1129.  
  1130.  
  1131.        The INTERFACE  and Debug  dictionary hash  tables are  Global in Scope
  1132.        even though the symbols accessed directly via either hash table may be
  1133.        private.   On the  other hand,  other hash  tables are purely local in
  1134.        scope.   For example,  the fields declared within a record are reached
  1135.        via a small local hash table, as are the arguments and local variables
  1136.        declared within  procedures and  functions.   Even  OBJECTS  use  this
  1137.        technique to provide access to Methods and Object Fields.
  1138.  
  1139.        Access to  such local  scope fields/methods  requires use of qualified
  1140.        names which  ensures conformity  to Pascal scope rules.  The method is
  1141.        truly simple and elegant.
  1142.  
  1143.  
  1144.  
  1145.        5.4.1.3 SPECIAL CASES
  1146.  
  1147.  
  1148.        The SYSTEM.TPU  Unit is  a special case.  Its INTERFACE hash table has
  1149.        apparently been  "hand-tuned" for  small size  and  it  contains  only
  1150.        sixteen (16) entries.  I have always felt that "hand-coding" must have
  1151.        been used  to achieve  the SYSTEM  unit.  The implications of the file
  1152.        "SYSTEM.TPS" required  for compilation  of the  SYSTEM  unit  seem  to
  1153.        support this  opinion.  Certainly, there are aspects of this unit that
  1154.        appear conventional,  but there  is much that is unique and apparently
  1155.        not the  result of PASCAL coding.  Library sources should help clarify
  1156.        this.  (See 2.2 SYSTEM UNIT on page 8)
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.        ──────────────────────────────────────────────────────────────────────
  1185.        June 6, 1991                                                   Page 19
  1186.  
  1187.  
  1188.  
  1189.                            Inside TURBO Pascal Unit Files            
  1190.        ──────────────────────────────────────────────────────────────────────
  1191.  
  1192.        5.4.2 NAME ENTRIES
  1193.  
  1194.  
  1195.        This is  the structure  that anchors  all  information  known  by  the
  1196.        compiler about any symbol.  The format is as follows:
  1197.  
  1198.        DNameRec = RECORD
  1199.             HLink : LL;          { Hash Chain Link; Resolves Collisions }
  1200.             DForm : Char;        { Symbol Class }
  1201.             DSymb : STRING[63];  { Text of Symbol (UPPER-CASE) }
  1202.        END;
  1203.  
  1204.          HLink:  An LL  which points  to the  next (previous) symbol in the
  1205.                  same unit which had the same hash function value.
  1206.  
  1207.          DForm:  A character  that defines  the class the symbol belongs to
  1208.                  and defines  the format of the Name Stub which follows the
  1209.                  Name Entry.   If  the symbol  is declared in the component
  1210.                  list of  the "private" part of an Object declaration, then
  1211.                  this character  is modified  by adding  $80 to its ordinal
  1212.                  value.  Thus, an ordinary Function, Procedure or Method is
  1213.                  of category  "S" while  a private  Method is  of  category
  1214.                  Chr(Ord('S')+$80).
  1215.  
  1216.          DSymb:  A String  (in the  Pascal sense)  of  variable  size  that
  1217.                  contains the  text of  the symbol  (in UPPER-CASE  letters
  1218.                  only).   The SizeOf  function is  not  defined  for  these
  1219.                  strings since they are truncated to match the symbol size.
  1220.                  The "value"  of the  SizeOf function  can be determined by
  1221.                  adding  1  to  the  first  byte  in  the  string.    Thus,
  1222.                  Ord(Symbol[0])+1 is  the expression  that defines the Size
  1223.                  of the  symbol string.  Turbo Pascal defines a symbol as a
  1224.                  string of  relatively arbitrary size, the most significant
  1225.                  63 characters  of which  will be stored in the dictionary.
  1226.                  Thus, we  conclude that  the maximum size of such a string
  1227.                  is 64 bytes.
  1228.  
  1229.  
  1230.  
  1231.        5.4.3 NAME STUBS
  1232.  
  1233.  
  1234.        Name Stubs  immediately follow their respective Name Entries and their
  1235.        format is  determined by  the class  code in  the  Name  Entry.    The
  1236.        function of the stub is to organize the information appropriate to the
  1237.        symbol and provide a means of accessing additional information such as
  1238.        type descriptors,  constant values, parameter lists and nested scopes.
  1239.        The format of each Stub is presented in the following sub-sections.
  1240.  
  1241.  
  1242.  
  1243.        5.4.3.1 LABEL DECLARATIVES ("O")
  1244.  
  1245.  
  1246.        This Stub consists of a WORD whose function is (as yet) unknown.
  1247.  
  1248.        ──────────────────────────────────────────────────────────────────────
  1249.        June 6, 1991                                                   Page 20
  1250.  
  1251.  
  1252.  
  1253.                            Inside TURBO Pascal Unit Files            
  1254.        ──────────────────────────────────────────────────────────────────────
  1255.  
  1256.        5.4.3.2 UN-TYPED CONSTANTS ("P")
  1257.  
  1258.  
  1259.        Format is as follows (CASE fragment):
  1260.  
  1261.           'P':(                 { --- For Untyped Constants ---  }
  1262.                sPTD : LG;       { to type descriptor             }
  1263.                sPV1 : LongInt;  { constant value - size variable }
  1264.               );
  1265.  
  1266.          sPTD:   An LG  which points  to  a  Type  Descriptor  (usually  in
  1267.                  SYSTEM.TPU).     This  establishes   the  minimum  storage
  1268.                  requirement for  the constant.   The  rules vary  with the
  1269.                  type, but  the size  of the  constant  data  field  (which
  1270.                  follows) is defined using the Type Descriptor(s).
  1271.  
  1272.          sPV1:   The value  of the constant.  For ordinal types, this value
  1273.                  is stored as a LONGINT (size=4 bytes).  For Floating-Point
  1274.                  types, the  size is  implicit in  the type  itself.    For
  1275.                  String types,  the size  is determined  from the length of
  1276.                  the string  which is  stored in  the initial  byte of  the
  1277.                  constant.
  1278.  
  1279.  
  1280.  
  1281.        5.4.3.3 NAMED TYPES ("Q")
  1282.  
  1283.  
  1284.        This Stub  consists of  an  LG  (4-bytes)  that  points  to  the  Type
  1285.        Descriptor for this symbol.
  1286.  
  1287.  
  1288.  
  1289.  
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295.  
  1296.  
  1297.  
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312.        ──────────────────────────────────────────────────────────────────────
  1313.        June 6, 1991                                                   Page 21
  1314.  
  1315.  
  1316.  
  1317.                            Inside TURBO Pascal Unit Files            
  1318.        ──────────────────────────────────────────────────────────────────────
  1319.  
  1320.        5.4.3.4 VARIABLES, FIELDS, TYPED CONS ("R")
  1321.  
  1322.  
  1323.        This Stub contains information required to allocate and describe these
  1324.        types of entities.  The format and content is as follows:
  1325.  
  1326.           'R': (                     { -- Variable, Field, Object  --  }
  1327.                 sRAM: Byte;          {   allocation method codes:      }
  1328.                 sRVF: CASE sRAM: Byte Of
  1329.                       $02,$06,
  1330.                       $22,$26:  (ROfs : Word;  { allocation offset (BP)  }
  1331.                                  ROB  : Word); { To Parent Scope/Zero    }
  1332.                       $00,$01:  (TOfs : Word;  { allocation offset in map}
  1333.                                  TOB  : LL);   { offset in VAR/CONST Map }
  1334.                        $03:     (AFar : Word); { FAR Pointer to Location }
  1335.                        $08:     (Bofs : Word;  { Offset-Record Relative  }
  1336.                                  RChn : LL);   { To Next Field/Method    }
  1337.                        $10:     (QLG  : LG);   { to Stub of Allocator    }
  1338.                       END;
  1339.                 sRTD: LG);           { to Type Descriptor              }
  1340.  
  1341.          sRAM:   A one-byte flag that precisely identifies the class of the
  1342.                  item being described.  The known values and their apparent
  1343.                  meanings follow:
  1344.  
  1345.                  $00 -> Global Variables (Allocated in DS);
  1346.                  $01 -> Typed Constants (Allocated in DS);
  1347.                  $02 -> Procedure LOCAL Variables on STACK;
  1348.                  $03 -> Variables at Absolute Addresses;
  1349.                  $06 -> ADDRESS Arguments allocated on STACK; (This is now
  1350.                         used only for SELF in Method calls;)
  1351.                  $08 -> Fields sub-allocated in RECORDS and OBJECTS, plus
  1352.                         METHODS declared for OBJECTS.
  1353.                  $10 -> Variable Equivalenced to another via the
  1354.                         Absolute Clause;
  1355.                  $22 -> Arguments whose VALUEs are passed on the stack;
  1356.                  $26 -> Arguments whose ADDRESSes are passed on the stack.
  1357.  
  1358.          sRVF:   Two words  whose content  vary with sRAM above.  Their are
  1359.                  shown as case variants in the following:
  1360.  
  1361.                  $02,$06,$22,$26: {arguments}
  1362.  
  1363.          sRVF.ROfs:   Word -- Offset relative to either DS or BP.
  1364.          sRVF.ROB:    Word -- LL to Dict Header of Parent Scope, or zero.
  1365.  
  1366.                  $00,$01: {VAR's or typed CONSTs}
  1367.  
  1368.          sRVF.TOfs:   Word -- Offset relative to allocation area origin;
  1369.          sRVF.TOB:    Word -- Offset to entry in VAR/CONST Map for item
  1370.                              allocation;
  1371.  
  1372.                  $03: {Absolute Address Variable}
  1373.  
  1374.          sRVF.AFar:   POINTER -- FAR Pointer to Absolute Memory Address.
  1375.  
  1376.        ──────────────────────────────────────────────────────────────────────
  1377.        June 6, 1991                                                   Page 22
  1378.  
  1379.  
  1380.  
  1381.                            Inside TURBO Pascal Unit Files            
  1382.        ──────────────────────────────────────────────────────────────────────
  1383.  
  1384.                  $08: {Record/Object Fields/Methods}
  1385.  
  1386.          sRVF.BOfs:   Word -- Allocation Offset within Record/Object;
  1387.          sRVF.RChn:   Word -- LL to next Field/Method.
  1388.  
  1389.                  $10: {Absolute Equivalences}
  1390.  
  1391.          sRVF.QLG:    LG   -- LG to STUB of variable/parameter declaration
  1392.                              that actually establishes the allocation;
  1393.  
  1394.          sRTD:   An LG  that locates  the proper  Type Descriptor  for this
  1395.                  symbol.
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405.  
  1406.  
  1407.  
  1408.  
  1409.  
  1410.  
  1411.  
  1412.  
  1413.  
  1414.  
  1415.  
  1416.  
  1417.  
  1418.  
  1419.  
  1420.  
  1421.  
  1422.  
  1423.  
  1424.  
  1425.  
  1426.  
  1427.  
  1428.  
  1429.  
  1430.  
  1431.  
  1432.  
  1433.  
  1434.  
  1435.  
  1436.  
  1437.  
  1438.  
  1439.  
  1440.        ──────────────────────────────────────────────────────────────────────
  1441.        June 6, 1991                                                   Page 23
  1442.  
  1443.  
  1444.  
  1445.                            Inside TURBO Pascal Unit Files            
  1446.        ──────────────────────────────────────────────────────────────────────
  1447.  
  1448.        5.4.3.5 SUBPROGRAMS & METHODS ("S")
  1449.  
  1450.  
  1451.        Subprograms (PROC's),  especially since  Object Methods are supported,
  1452.        have a rather involved stub.  Its format is as follows:
  1453.  
  1454.           'S': (                { ------ User Subprograms ----- }
  1455.                 sSTp : Byte;    { BIT Encoded Flags             }
  1456.                 sSxx : Byte;    { More Attribute Flags?         }
  1457.                 sSPM : Word;    { Code byte count if INLINE,    }
  1458.                                 { else, offset to PROC Map      }
  1459.                 sSPS : LL;      { to containing scope or zero   }
  1460.                 sSHT : LL;      { to local scope hash table     }
  1461.                 sSVM : Word);   { VMT Offset-VIRTUAL Method PTR }
  1462.  
  1463.          sSTP:   A byte  that contains  bit-switches that  seem to describe
  1464.                  the Call  Model and  imply the  size of  this stub.  These
  1465.                  switches determine what kind of code (if any) is generated
  1466.                  when the  PROC is  referenced.  The observed values are as
  1467.                  follows:
  1468.  
  1469.                  xxxxx001 -> PROC uses FAR Call Model;
  1470.                  xxxx0010 -> PROC uses INLINE Model (no Call);
  1471.                  xxxx0100 -> PROC uses INTERRUPT Model (no Call);
  1472.                  xxxx100x -> PROC has EXTERNAL attribute;
  1473.                  xxx1xxxx -> PROC uses METHOD Call Model;
  1474.                  x011xxxx -> PROC is a CONSTRUCTOR Method;
  1475.                  x101xxxx -> PROC is a DESTRUCTOR Method;
  1476.                  1xxxxxxx -> PROC has ASSEMBLER directive.
  1477.  
  1478.          sSxx:   A byte  whose function  is not  yet fully  known.   In the
  1479.                  Windows  compiler  it  is  copied  into  the  PROC  Map  -
  1480.                  presumably for  use  by  the  linker  or  debugger.    Bit
  1481.                  positions firmly established are as follows (7..0):
  1482.  
  1483.                  7-6: always zero?
  1484.                  5:   ????
  1485.                  4:   Dynamic Call Model using DMT
  1486.                  3-2: 11 = DLL PROC Referenced by NAME
  1487.                       01 = DLL PROC Referenced by INDEX
  1488.                  1:   ????
  1489.                  0:   always zero???
  1490.  
  1491.          sSPM:   A Word  whose interpretation  depends on whether or not we
  1492.                  have an  INLINE Declarative  Subprogram.   If this  is  an
  1493.                  INLINE Declarative Subprogram, then this word contains the
  1494.                  byte-count of  the INLINE  code text  at the  end of  this
  1495.                  stub.   Otherwise, this word is the offset within the PROC
  1496.                  Map that locates the object code for this Subprogram.
  1497.  
  1498.          sSPS:   A Word  that contains  an LL  which locates the containing
  1499.                  scope in the dictionary, or zero if none.
  1500.  
  1501.  
  1502.  
  1503.  
  1504.        ──────────────────────────────────────────────────────────────────────
  1505.        June 6, 1991                                                   Page 24
  1506.  
  1507.  
  1508.  
  1509.                            Inside TURBO Pascal Unit Files            
  1510.        ──────────────────────────────────────────────────────────────────────
  1511.  
  1512.          sSHT:   A Word  that contains  an LL  which locates the local Hash
  1513.                  Table for  this scope.  A local hash table provides access
  1514.                  to all  formal parameters of the Subprogram as well as all
  1515.                  Symbols whose  declarations are local to the scope of this
  1516.                  Subprogram.
  1517.  
  1518.          sSVM:   A Word that is zero unless the symbol is a Virtual Method.
  1519.                  In this  case, then  the content  is the offset within the
  1520.                  VMT for  the owning  object that  defines  where  the  FAR
  1521.                  POINTER to this Virtual Method is stored.
  1522.  
  1523.          +0A:    A complete  Type-Descriptor  for  this  Subprogram.    The
  1524.                  length is  variable and  depends upon the number of Formal
  1525.                  Parameters declared in the header.  (See 5.4.4.3.5 on page
  1526.                  34).
  1527.  
  1528.          +??:    If  this   Symbol   represents   an   INLINE   Declarative
  1529.                  Subprogram, then  the object-code  text begins  here.  The
  1530.                  byte-count of the text is stored in sSPM in this stub.
  1531.  
  1532.  
  1533.  
  1534.        5.4.3.6 TURBO STD PROCEDURES ("T")
  1535.  
  1536.  
  1537.        This Stub consists of two bytes, the first of which is unique for each
  1538.        procedure and  increments by  4.   I have  found nothing in the SYSTEM
  1539.        unit (which  is where  this entry  appears) that  this seems  directly
  1540.        related to.  The second byte is always zero.
  1541.  
  1542.  
  1543.  
  1544.        5.4.3.7 TURBO STD FUNCTIONS ("U")
  1545.  
  1546.  
  1547.        This Stub consists of two bytes, the first of which is unique for each
  1548.        function and increments by 4.  I have found nothing in the SYSTEM unit
  1549.        (which is  where this  entry appears) that this seems directly related
  1550.        to.   I wouldn't  be surprised if this byte were an index into a TURBO
  1551.        compiler table that points to specialized parse tables/action routines
  1552.        for handling these functions and their non-standard parameter lists.
  1553.  
  1554.        The second byte seems to be a flag having the values $00, $40 and $C0.
  1555.        I strongly  suspect that  the flag  $C0 marks  exactly those functions
  1556.        which may  be evaluated at compile-time.  The meaning behind the other
  1557.        values is not known to me.
  1558.  
  1559.  
  1560.  
  1561.        5.4.3.8 TURBO STD "NEW" ROUTINE ("V")
  1562.  
  1563.  
  1564.        This Stub consists of a WORD whose function is (as yet) unknown.  This
  1565.        is the  only Standard  Turbo routine that can behave as a procedure as
  1566.        well as a function (returning a pointer value).
  1567.  
  1568.        ──────────────────────────────────────────────────────────────────────
  1569.        June 6, 1991                                                   Page 25
  1570.  
  1571.  
  1572.  
  1573.                            Inside TURBO Pascal Unit Files            
  1574.        ──────────────────────────────────────────────────────────────────────
  1575.  
  1576.        5.4.3.9 TURBO STD PORT ARRAYS ("W")
  1577.  
  1578.  
  1579.        This Stub  consists of  a byte whose value is 0 for byte arrays, and 1
  1580.        for word arrays.
  1581.  
  1582.  
  1583.  
  1584.        5.4.3.10 TURBO STD EXTERNAL VARIABLES ("X")
  1585.  
  1586.  
  1587.        This Stub  consists of  an  LG  (4-bytes)  that  points  to  the  Type
  1588.        Descriptor for  this symbol.  (These are used for the arrays MEM, MEMW
  1589.        and MEML.)
  1590.  
  1591.  
  1592.  
  1593.        5.4.3.11 UNITS ("Y")
  1594.  
  1595.  
  1596.        Unit Stubs have the following content:
  1597.  
  1598.          +00:    A Word  whose apparently  reserved for use by the Compiler
  1599.                  or Linker.
  1600.  
  1601.          +02:    A Word that seems to contain some kind of "signature" used
  1602.                  to detect  inconsistent Unit Versions.  Borland calls this
  1603.                  a "unit  version number,  which is basically a checksum of
  1604.                  the interface  part."   I have  seen a thread in CIS which
  1605.                  says that it is a CRC value.  Food for thought?
  1606.  
  1607.          +04:    A Word  that contains  an LL  which locates  the Successor
  1608.                  Unit in  the "Uses"  list.   In fact,  the "Uses" lists of
  1609.                  both the INTERFACE and IMPLEMENTATION sections of the Unit
  1610.                  are merged  by this  Word into  a single list.  A value of
  1611.                  zero is used to indicate no successor.
  1612.  
  1613.          +06:    A Word  that contains  an LL which locates the Predecessor
  1614.                  Unit in  the "Uses" list.  For the SYSTEM unit entry, this
  1615.                  value is  always zero to indicate no predecessor.  For the
  1616.                  Unit being compiled, this LL locates the final Unit in the
  1617.                  combined "Uses" list.
  1618.  
  1619.        In effect,  the two  LL's at  offsets 0004 and 0006 organize the units
  1620.        into both  forward and backward linked chains.  The entry for the unit
  1621.        being compiled  is effectively  the head  of both  the forward and the
  1622.        backward chains.  The final unit in the merged "Uses" list is the tail
  1623.        of the  forward chain, and the SYSTEM unit is the tail of the backward
  1624.        chain.
  1625.  
  1626.  
  1627.  
  1628.  
  1629.  
  1630.  
  1631.  
  1632.        ──────────────────────────────────────────────────────────────────────
  1633.        June 6, 1991                                                   Page 26
  1634.  
  1635.  
  1636.  
  1637.                            Inside TURBO Pascal Unit Files            
  1638.        ──────────────────────────────────────────────────────────────────────
  1639.  
  1640.        5.4.4 TYPE DESCRIPTORS
  1641.  
  1642.  
  1643.        Type Descriptors  store much  of the semantic information that applies
  1644.        to the  symbols declared  in the  unit.  Implementation details can be
  1645.        managed using  high-level abstractions  and these  abstractions can be
  1646.        shared.
  1647.  
  1648.  
  1649.  
  1650.        5.4.4.1 SCOPE
  1651.  
  1652.  
  1653.        Type Descriptor  sharing can  occur across  the boundaries  which  are
  1654.        implicit in  unit modules.   Thus,  a type  defined in one unit may be
  1655.        "imported" by  some other  module.  Also, the pre-defined Pascal Types
  1656.        (plus the  Turbo Pascal extensions) are defined in the SYSTEM.TPU unit
  1657.        and there  needs to  be a  means of  "importing" such Type Descriptors
  1658.        during compilation.  This is precisely the objective of the LG locator
  1659.        (see Section  3.2 on  Page 9).   Type  Descriptors  are  NEVER  copied
  1660.        between units.  The binding always occurs by reference at compile time
  1661.        and this helps support the technique of modifying a unit and compiling
  1662.        it to a .TPU file, then re-compiling all units/programs that "USE" it.
  1663.  
  1664.        Type Descriptors  have many  roles so  their format  varies.   We have
  1665.        divided these  structures into  two parts:   The PREFIX Part (which is
  1666.        always present  and) whose  format is  fairly constant  and the SUFFIX
  1667.        Part whose  content and format depends on the attributes that are part
  1668.        of the type definition.
  1669.  
  1670.  
  1671.  
  1672.  
  1673.  
  1674.  
  1675.  
  1676.  
  1677.  
  1678.  
  1679.  
  1680.  
  1681.  
  1682.  
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688.  
  1689.  
  1690.  
  1691.  
  1692.  
  1693.  
  1694.  
  1695.  
  1696.        ──────────────────────────────────────────────────────────────────────
  1697.        June 6, 1991                                                   Page 27
  1698.  
  1699.  
  1700.  
  1701.                            Inside TURBO Pascal Unit Files            
  1702.        ──────────────────────────────────────────────────────────────────────
  1703.  
  1704.        5.4.4.2 PREFIX PART
  1705.  
  1706.  
  1707.        The Prefix  Part of  every Type  Descriptor consists of six (6) bytes.
  1708.        The usage  is consistent for all types observed by this author and the
  1709.        format is as follows:
  1710.  
  1711.          +00:    A Byte  that identifies  the format  of the  Suffix  part.
  1712.                  This is essentially based on several high-level categories
  1713.                  which the Suffix Parts support directly.  The observed set
  1714.                  of values is as follows:
  1715.  
  1716.                  00h -> an un-typed entity;
  1717.                  01h -> an ARRAY type;
  1718.                  02h -> a RECORD type;
  1719.                  03h -> an OBJECT type;
  1720.                  04h -> a FILE type (other than TEXT);
  1721.                  05h -> a TEXT File type;
  1722.                  06h -> a SUBPROGRAM type;
  1723.                  07h -> a SET type;
  1724.                  08h -> a POINTER type;
  1725.                  09h -> a STRING type;
  1726.                  0Ah -> an 8087 Floating-Point type;
  1727.                  0Bh -> a REAL type;
  1728.                  0Ch -> a Fixed-Point ordinal type;
  1729.                  0Dh -> a BOOLEAN type;
  1730.                  0Eh -> a CHAR type;
  1731.                  0Fh -> an Enumerated ordinal type.
  1732.  
  1733.          +01:    A Byte  used as a modifier.  Since the above scheme is too
  1734.                  general for  machine-dependent  details  such  as  storage
  1735.                  width  and  sign  control,  this  modifier  byte  supplies
  1736.                  additional data.   The author has identified several cases
  1737.                  in which  this information is vital but has not spent very
  1738.                  much time  on the  subject.  The chief areas of importance
  1739.                  seem to  be in  the 8087  Floating-Point  types,  and  the
  1740.                  Fixed-Point ordinal  types.   The semantics  seem to be as
  1741.                  follows:
  1742.  
  1743.                  0A 00 -> The type "SINGLE"
  1744.                  0A 02 -> The type "EXTENDED"
  1745.                  0A 04 -> The type "DOUBLE"
  1746.                  0A 06 -> The type "COMP"
  1747.  
  1748.                  0C 00 -> an un-named BYTE integer
  1749.                  0C 01 -> The type "SHORTINT"
  1750.                  0C 02 -> The type "BYTE"
  1751.                  0C 04 -> an un-named WORD integer
  1752.                  0C 05 -> The type "INTEGER"
  1753.                  0C 06 -> The type "WORD"
  1754.                  0C 0C -> an un-named double-word integer
  1755.                  0C 0D -> The type "LONGINT"
  1756.  
  1757.  
  1758.  
  1759.  
  1760.        ──────────────────────────────────────────────────────────────────────
  1761.        June 6, 1991                                                   Page 28
  1762.  
  1763.  
  1764.  
  1765.                            Inside TURBO Pascal Unit Files            
  1766.        ──────────────────────────────────────────────────────────────────────
  1767.  
  1768.          +02:    A Word  that contains  the number of bytes of storage that
  1769.                  are required  to contain  an object/entity  of this  type.
  1770.                  For types  that represent variable-length objects/entities
  1771.                  such as  strings, this  word may define the value returned
  1772.                  by the SIZEOF function as applied to the type.
  1773.  
  1774.                  This word  is probably  of value during compilation of un-
  1775.                  typed CONST's since the size of their Stubs depend on this
  1776.                  field.  For STRING types however, the length descriptor is
  1777.                  part of the string itself.
  1778.  
  1779.          +04     A Word  that is zero (for DOS units) unless the descriptor
  1780.                  is for  an Object Method.  In this case, the content is an
  1781.                  LL to  the Name  Entry of  the SUCCEEDING  Method for  the
  1782.                  Object, in  order of  declaration, or  zero if none.  Some
  1783.                  Windows units  (e.g., SYSTEM)  have non-zero  values  here
  1784.                  whose function is not known.
  1785.  
  1786.  
  1787.  
  1788.        5.4.4.3 SUFFIX PARTS
  1789.  
  1790.  
  1791.        Suffix Parts further refine the implementation details of the type and
  1792.        also provide  subrange constraints  where appropriate.   In some cases
  1793.        the Suffix  part is  empty since  all semantic  data for  the type  is
  1794.        contained in the Prefix part.
  1795.  
  1796.  
  1797.  
  1798.        5.4.4.3.1 UN-TYPED
  1799.  
  1800.  
  1801.        This Suffix Part is empty.  Nothing is known about an un-typed entity.
  1802.  
  1803.  
  1804.  
  1805.        5.4.4.3.2 STRUCTURED TYPES
  1806.  
  1807.  
  1808.        The structured  types represent  aggregates of  lower-level types.  We
  1809.        include ARRAY,  RECORD, OBJECT,  FILE, TEXT,  SET, POINTER  and STRING
  1810.        types in this category.
  1811.  
  1812.  
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820.  
  1821.  
  1822.  
  1823.  
  1824.        ──────────────────────────────────────────────────────────────────────
  1825.        June 6, 1991                                                   Page 29
  1826.  
  1827.  
  1828.  
  1829.                            Inside TURBO Pascal Unit Files            
  1830.        ──────────────────────────────────────────────────────────────────────
  1831.  
  1832.        5.4.4.3.2.1 ARRAY TYPES
  1833.  
  1834.  
  1835.        The Suffix  Part of  the ARRAY type is so constructed as to be able to
  1836.        support recursive  or nested  definition of arrays.  The suffix format
  1837.        is as follows:
  1838.  
  1839.          +00:    An LG that locates the Type Descriptor for the "base-type"
  1840.                  of the  array.   This is  the type  of  the  entity  being
  1841.                  arrayed (which may itself be an array).
  1842.  
  1843.          +04:    An LG  that locates  the Type  Descriptor  for  the  array
  1844.                  bounds which is a constrained ordinal type or subrange.
  1845.  
  1846.  
  1847.  
  1848.        5.4.4.3.2.2 RECORD TYPES
  1849.  
  1850.  
  1851.        RECORD types  have nested  scopes.   The Suffix  part provides  a base
  1852.        structure by  which to  locate the  fields local  to the  scope of the
  1853.        Record type itself.  The format is as follows:
  1854.  
  1855.          +00:    A Word containing an LL which locates the local Hash Table
  1856.                  that provides access to the fields in the nested scope.
  1857.  
  1858.          +02:    A Word  containing an  LL which  locates the Name Entry of
  1859.                  the initial  field in  the nested  scope.  This supports a
  1860.                  "left-to-right" traversal of the fields in a record.
  1861.  
  1862.  
  1863.  
  1864.  
  1865.  
  1866.  
  1867.  
  1868.  
  1869.  
  1870.  
  1871.  
  1872.  
  1873.  
  1874.  
  1875.  
  1876.  
  1877.  
  1878.  
  1879.  
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886.  
  1887.  
  1888.        ──────────────────────────────────────────────────────────────────────
  1889.        June 6, 1991                                                   Page 30
  1890.  
  1891.  
  1892.  
  1893.                            Inside TURBO Pascal Unit Files            
  1894.        ──────────────────────────────────────────────────────────────────────
  1895.  
  1896.        5.4.4.3.2.3 OBJECT TYPES
  1897.  
  1898.  
  1899.        OBJECT types also have nested scopes.  The Suffix part provides a base
  1900.        structure by which to locate the fields and METHODS local to the scope
  1901.        of  the  OBJECT  type  itself.    In  addition,  inheritance  and  VMT
  1902.        particulars are stored.  The format is as follows:
  1903.  
  1904.          +00:    A Word containing an LL which locates the local Hash Table
  1905.                  that provides  access to  the fields  and METHODS local to
  1906.                  the nested scope.
  1907.  
  1908.          +02:    A Word  containing an  LL which  locates the Name Entry of
  1909.                  the initial  field or  METHOD in  the nested  scope.  This
  1910.                  supports a  "left-to-right" traversal  of the  fields  and
  1911.                  METHODS in an OBJECT.
  1912.  
  1913.          +04:    An LG  which locates  the Type  Descriptor of  the  Parent
  1914.                  Object.  This field is zero if there is no such Parent.
  1915.  
  1916.          +08:    A Word  which contains  the size  in bytes  of the VMT for
  1917.                  this Object.   This field is zero if the object employs no
  1918.                  Virtual Methods, Constructors or Destructors.
  1919.  
  1920.          +0A:    A Word which contains the offset within the CONST DSeg Map
  1921.                  that locates  the VMT  skeleton or template segment.  This
  1922.                  field equals  FFFFh  if  the  object  employs  no  Virtual
  1923.                  Methods, Constructors or Destructors.
  1924.  
  1925.          +0C:    A Word which contains the offset within an Object instance
  1926.                  where the NEAR POINTER to the VMT for the object is stored
  1927.                  (within the DATA SEGMENT).  This field equals FFFFh if the
  1928.                  object  employs   no  Virtual   Methods,  Constructors  or
  1929.                  Destructors.
  1930.  
  1931.          +0E:    A Word  which contains  an LL which locates the Name Entry
  1932.                  for the name of the OBJECT itself.
  1933.  
  1934.          +10:    A Word  containing $FFFF  in DOS  units.  In WINDOWS units
  1935.                  this word  contains the  offset within  the CONST DSeg Map
  1936.                  that locates  the DMT  skeleton or template segment.  This
  1937.                  field equals  FFFFh  if  the  object  employs  no  Dynamic
  1938.                  Methods.
  1939.  
  1940.          +12:    Three Words (not yet understood) containing zeroes.
  1941.  
  1942.  
  1943.  
  1944.        5.4.4.3.2.4 FILE (NON-TEXT) TYPES
  1945.  
  1946.  
  1947.        This Suffix  consists of an LG that locates the Type Descriptor of the
  1948.        base type  of the  file.  Note that the Type Descriptor may be that of
  1949.        an un-typed entity (for un-typed files).
  1950.  
  1951.  
  1952.        ──────────────────────────────────────────────────────────────────────
  1953.        June 6, 1991                                                   Page 31
  1954.  
  1955.  
  1956.  
  1957.                            Inside TURBO Pascal Unit Files            
  1958.        ──────────────────────────────────────────────────────────────────────
  1959.  
  1960.        5.4.4.3.2.5 TEXT FILE TYPES
  1961.  
  1962.  
  1963.        This Suffix  consists of an LG that locates the Type Descriptor of the
  1964.        base type of the file -- in this case SYSTEM.CHAR.
  1965.  
  1966.  
  1967.  
  1968.        5.4.4.3.2.6 SET TYPES
  1969.  
  1970.  
  1971.        This Suffix  consists of  an LG  that locates the base-type of the set
  1972.        itself.    Pascal  limits  such  entities  to  simple  ordinals  whose
  1973.        cardinality is limited to 256.
  1974.  
  1975.  
  1976.  
  1977.        5.4.4.3.2.7 POINTER TYPES
  1978.  
  1979.  
  1980.        This Suffix consists of an LG that locates the base-type of the entity
  1981.        pointed at.
  1982.  
  1983.  
  1984.  
  1985.        5.4.4.3.2.8 STRING TYPES
  1986.  
  1987.  
  1988.        This is a special case of an ARRAY type.  The format is as follows:
  1989.  
  1990.          +00:    An LG to the Type Descriptor SYSTEM.CHAR which is the base
  1991.                  type of all Turbo Pascal Strings.
  1992.  
  1993.          +04:    An  LG  to  the  Type  Descriptor  for  the  array  bounds
  1994.                  constraints for the string.  When the unconstrained STRING
  1995.                  type is  used, this points to SYSTEM.BYTE which is defined
  1996.                  as a subrange 0..255.
  1997.  
  1998.  
  1999.  
  2000.        5.4.4.3.3 FLOATING-POINT TYPES
  2001.  
  2002.  
  2003.        The Suffix  part for  all Floating-Point  types is  EMPTY.   All  data
  2004.        needed to  specify these  approximate number types is contained in the
  2005.        Prefix part.   The  Types included  in this  class are SINGLE, DOUBLE,
  2006.        EXTENDED, COMP and REAL.
  2007.  
  2008.  
  2009.  
  2010.        5.4.4.3.4 ORDINAL TYPES
  2011.  
  2012.  
  2013.        The Ordinal  Types consist  of the  various "integer"  types plus  the
  2014.        BOOLEAN, CHAR and Enumerated types.
  2015.  
  2016.        ──────────────────────────────────────────────────────────────────────
  2017.        June 6, 1991                                                   Page 32
  2018.  
  2019.  
  2020.  
  2021.                            Inside TURBO Pascal Unit Files            
  2022.        ──────────────────────────────────────────────────────────────────────
  2023.  
  2024.        5.4.4.3.4.1 "INTEGERS"
  2025.  
  2026.  
  2027.        These types  include BYTE, SMALLINT, WORD, INTEGER and LONGINT.  Their
  2028.        Suffix parts are identical in format:
  2029.  
  2030.          +00:    A double-word  containing the  LOWER bound of the subrange
  2031.                  constraint on the type;
  2032.  
  2033.          +04:    A double-word  containing the  UPPER bound of the subrange
  2034.                  constraint on the type;
  2035.  
  2036.          +08:    An LG  that locates  the Type  Descriptor of  the  largest
  2037.                  upward compatible  type.  This is the Type Descriptor that
  2038.                  is used  to control  the width  of an un-typed constant in
  2039.                  the dictionary  stub.  For the "integer" types, this is an
  2040.                  LG to SYSTEM.LONGINT.
  2041.  
  2042.  
  2043.  
  2044.        5.4.4.3.4.2 BOOLEANS
  2045.  
  2046.  
  2047.        This type Suffix has the following format:
  2048.  
  2049.          +00:    A double-word  containing the  LOWER bound of the subrange
  2050.                  constraint on the type;
  2051.  
  2052.          +04:    A double-word  containing the  UPPER bound of the subrange
  2053.                  constraint on the type;
  2054.  
  2055.          +08:    An LG  that locates  the Type  Descriptor  SYSTEM.BOOLEAN.
  2056.                  There is no "upward compatible" type.
  2057.  
  2058.  
  2059.  
  2060.        5.4.4.3.4.3 CHARS
  2061.  
  2062.  
  2063.        This type Suffix has the following format:
  2064.  
  2065.          +00:    A double-word  containing the  LOWER bound of the subrange
  2066.                  constraint on the type;
  2067.  
  2068.          +04:    A double-word  containing the  UPPER bound of the subrange
  2069.                  constraint on the type;
  2070.  
  2071.          +08:    An LG that locates the Type Descriptor SYSTEM.CHAR.  There
  2072.                  is no "upward compatible" type.
  2073.  
  2074.  
  2075.  
  2076.  
  2077.  
  2078.  
  2079.  
  2080.        ──────────────────────────────────────────────────────────────────────
  2081.        June 6, 1991                                                   Page 33
  2082.  
  2083.  
  2084.  
  2085.                            Inside TURBO Pascal Unit Files            
  2086.        ──────────────────────────────────────────────────────────────────────
  2087.  
  2088.        5.4.4.3.4.4 ENUMERATIONS
  2089.  
  2090.  
  2091.        This type Suffix is unusual and has the following format:
  2092.  
  2093.          +00:    A double-word  containing the  LOWER bound of the subrange
  2094.                  constraint on the type;
  2095.  
  2096.          +04:    A double-word  containing the  UPPER bound of the subrange
  2097.                  constraint on the type;
  2098.  
  2099.          +08:    An  LG  that  locates  the  Prefix  of  the  current  Type
  2100.                  Descriptor.  There is no upward compatible type.
  2101.  
  2102.        What follows  is a full-fledged SET Type Descriptor whose base type is
  2103.        the Type Descriptor of the Enumerated Type itself.  The author has not
  2104.        yet discovered the reason for this.
  2105.  
  2106.        At least  one case  has been  observed where  a set type descriptor is
  2107.        followed by  a word  containing zero  but I  know of  no  explanation.
  2108.        Could this be a (shudder) BUG in Turbo?
  2109.  
  2110.  
  2111.  
  2112.        5.4.4.3.5 SUBPROGRAM TYPES
  2113.  
  2114.  
  2115.        The length of this Suffix is variable.  The format is as follows:
  2116.  
  2117.          +00:    An LG  that locates  the Type  Descriptor of  the FUNCTION
  2118.                  result returned  by the Subprogram.  This field is zero if
  2119.                  the Subprogram is a PROCEDURE.
  2120.  
  2121.          +04:    A Word  that contains  the number  of Formal Parameters in
  2122.                  the Function/Procedure  header.   If non-zero,  then  this
  2123.                  word is  followed by the parameter list itself as a simple
  2124.                  array of parameter descriptors.
  2125.  
  2126.                  The format of a parameter descriptor is as follows:
  2127.  
  2128.                  0000: An LG that locates the Type Descriptor of the    
  2129.                        corresponding parameter;
  2130.  
  2131.                  0004: A Byte that identifies the parameter passing     
  2132.                        mechanism used for this entry as follows:
  2133.  
  2134.                        02h -> VALUE of parameter is passed on STACK,    
  2135.                        06h -> ADDRESS of parameter is passed on STACK.
  2136.  
  2137.  
  2138.  
  2139.  
  2140.  
  2141.  
  2142.  
  2143.  
  2144.        ──────────────────────────────────────────────────────────────────────
  2145.        June 6, 1991                                                   Page 34
  2146.  
  2147.  
  2148.  
  2149.                            Inside TURBO Pascal Unit Files            
  2150.        ──────────────────────────────────────────────────────────────────────
  2151.  
  2152.        6. MAPS AND LISTS
  2153.  
  2154.  
  2155.        The "MAPS  and LISTS"  are not part of the symbol dictionary.  Rather,
  2156.        these structures provide access to the Code and Data Segments produced
  2157.        by the  compiler or  included via  the {$L  name.OBJ} directive.   The
  2158.        format and  purpose (as  understood by  this author)  of each of these
  2159.        tables is explained in the following sections.
  2160.  
  2161.  
  2162.  
  2163.        6.1 PROC MAP
  2164.  
  2165.  
  2166.        The PROC  Map provides a means of associating the various Function and
  2167.        Procedure declarations  with Code  Segments and  DLL's.  There is some
  2168.        evidence that  the Compiler produces CODE (and DATA) Segments for EACH
  2169.        of the  Subprograms defined  in the  Unit as  well as for the un-named
  2170.        Unit Initialization  code block.  There is also evidence that EXTERNAL
  2171.        PROCs must be assembled separately in order to exploit fully the Turbo
  2172.        "Smart Linker" since Turbo Pascal places some significant restrictions
  2173.        on  EXTERNAL  routines  in  the  area  of  Segment  Names  and  Types.
  2174.        Specifically, only  code segments named "CODE" and data segments named
  2175.        "DATA" or  "CONST" will  be used  by the  "Smart Linker" as sources of
  2176.        code and  data for  inclusion in a Turbo Pascal .EXE file.  (Turbo 6.0
  2177.        relaxed Name  constraints but only one code segment per .OBJ remains a
  2178.        limitation).
  2179.  
  2180.        The first  entry in  the PROC  Map is reserved for Unit Initialization
  2181.        block.   If there  is no Unit Initialization block, this entry will be
  2182.        marked with  $FFFF.   In addition, each and every PROC in the Unit has
  2183.        an entry in this table (except for INLINE procs).
  2184.  
  2185.        If an  EXTERNAL routine  is included, then ALL PUBLIC PROC definitions
  2186.        in that  routine must  be declared  in the  Unit Source  Code with the
  2187.        EXTERNAL attribute.
  2188.  
  2189.        The size  of the  PROC Map  Table (in  Bytes) is  implied in  the Unit
  2190.        Header by the LL's named UHPMT and UNCMT.
  2191.  
  2192.        The Format of a single PROC Map Entry is as follows:
  2193.  
  2194.          +00:    A Word presumably reserved as a work area; always zero.
  2195.  
  2196.          +02:    A Word  which contains  Flags copied from sSxx in the Stub
  2197.                  for the  Subprogram.  This word is always zero for the DOS
  2198.                  compiler. (see 5.4.3.5, page 24)
  2199.  
  2200.          +04:    A Word  that contains an offset within the CSeg Map.  This
  2201.                  is used  to locate  the code  segment containing the PROC.
  2202.                  If the PROC is found in a DLL, then this word is an offset
  2203.                  within the  DLL List  to the DLL name (i.e., the file with
  2204.                  the .DLL extension).
  2205.  
  2206.  
  2207.  
  2208.        ──────────────────────────────────────────────────────────────────────
  2209.        June 6, 1991                                                   Page 35
  2210.  
  2211.  
  2212.  
  2213.                            Inside TURBO Pascal Unit Files            
  2214.        ──────────────────────────────────────────────────────────────────────
  2215.  
  2216.          +06:    A Word  that contains  an offset  within the  CODE Segment
  2217.                  that defines  the PROC  entry point  relative to  the load
  2218.                  point of  the referenced  CODE Segment  if local  to  this
  2219.                  unit.   For DLL  PROCS referenced  by "INDEX" this word is
  2220.                  the procedure  "INDEX" number  within the  DLL.   For  DLL
  2221.                  PROCS referenced  by "NAME" this word is an offset to that
  2222.                  name which is stored in the DLL List.
  2223.  
  2224.  
  2225.  
  2226.        6.2 CSEG MAP
  2227.  
  2228.  
  2229.        The CSeg  Map provides  a convenient  descriptor table  for each  CODE
  2230.        Segment present  in the  Unit and serves to relate these segments with
  2231.        the Segment  Relocation Data  and the  Segment Trace  Table.  It seems
  2232.        reasonable to infer that the "Smart Linker" is able to include/exclude
  2233.        code/data at the SEGMENT level only.
  2234.  
  2235.        The CSeg  Map is  an array  of fixed-length records whose format is as
  2236.        follows:
  2237.  
  2238.          +00:    A Word apparently reserved for use by TURBO.
  2239.  
  2240.          +02:    A Word that contains the Segment Length (in bytes).
  2241.  
  2242.          +04:    A Word  that contains  the Length of the Fix-Up Data Table
  2243.                  for this Code Segment (in bytes).
  2244.  
  2245.          +06:    A Word  that contains  the offset of the Trace Table Entry
  2246.                  for this  Segment (if it was compiled with DEBUG Support).
  2247.                  If there  is no  Trace Table  for this  segment, then this
  2248.                  Word contains FFFFh.
  2249.  
  2250.  
  2251.  
  2252.  
  2253.  
  2254.  
  2255.  
  2256.  
  2257.  
  2258.  
  2259.  
  2260.  
  2261.  
  2262.  
  2263.  
  2264.  
  2265.  
  2266.  
  2267.  
  2268.  
  2269.  
  2270.  
  2271.  
  2272.        ──────────────────────────────────────────────────────────────────────
  2273.        June 6, 1991                                                   Page 36
  2274.  
  2275.  
  2276.  
  2277.                            Inside TURBO Pascal Unit Files            
  2278.        ──────────────────────────────────────────────────────────────────────
  2279.  
  2280.        6.3 TYPED CONST DSEG MAP
  2281.  
  2282.  
  2283.        The CONST  DSeg Map  provides a  convenient descriptor  table for each
  2284.        DATA Segment  which was  spawned by the presence of Typed Constants or
  2285.        VMT's in the Pascal Code.  It serves to relate these segments with the
  2286.        Segment Fix-Up (relocation) Data and with the Code Segments that refer
  2287.        to these  DATA  elements.    One  entry  is  present  for  each  CONST
  2288.        declaration part containing typed constants and for each CONST segment
  2289.        linked from  an ".OBJ" file.  The CONST DSeg Map is an array of fixed-
  2290.        length records whose format is as follows:
  2291.  
  2292.          +00:    A Word apparently reserved for use by TURBO.
  2293.  
  2294.          +02:    A Word that contains the Segment Length (in bytes).
  2295.  
  2296.          +04:    A Word  that contains  the Length of the Fix-Up Data Table
  2297.                  for this DATA Segment (in bytes).
  2298.  
  2299.          +06:    A Word  that contains  an LL which locates the OBJECT that
  2300.                  owns this  VMT or  DMT template  or zero if the segment is
  2301.                  not a VMT or DMT template.
  2302.  
  2303.        One can  determine the defining block for a Typed Constant declaration
  2304.        and our  program attempts  to do  just that.    A  by-product  of  the
  2305.        dictionary mapping  algorithm allows  the declaring  block to be found
  2306.        and its  qualified name  printed.   This information  is also  used to
  2307.        explain fix-up  data as  to its  source.   Results will  be incomplete
  2308.        unless a really comprehensive dictionary is present in the unit.
  2309.  
  2310.  
  2311.  
  2312.        6.4 GLOBAL VAR DSEG MAP
  2313.  
  2314.  
  2315.        The VAR  DSeg Map provides a convenient descriptor table for each DATA
  2316.        Segment present in the Unit.
  2317.  
  2318.        One entry  exists for  each VAR  declaration part  whose scope  is not
  2319.        local to  a PROC  and so  is allocated  in the  DATA  Segment.    CODE
  2320.        Segments may  have references  to these in the CODE Fix-Up Data Table.
  2321.        Each EXTERNAL CSeg having a segment named DATA also spawns an entry in
  2322.        this table.
  2323.  
  2324.        The VAR  DSeg Map  is an array of fixed-length records whose format is
  2325.        as follows:
  2326.  
  2327.          +00:    A Word apparently reserved for use by TURBO.
  2328.  
  2329.          +02:    A Word  that contains the Segment Length (in bytes).  This
  2330.                  may be zero, especially if the EXTERNAL routine contains a
  2331.                  DATA segment  whose sole purpose is to declare one or more
  2332.                  EXTRN symbols  that  are  defined  in  some  DATA  segment
  2333.                  external to the Assembly.
  2334.  
  2335.  
  2336.        ──────────────────────────────────────────────────────────────────────
  2337.        June 6, 1991                                                   Page 37
  2338.  
  2339.  
  2340.  
  2341.                            Inside TURBO Pascal Unit Files            
  2342.        ──────────────────────────────────────────────────────────────────────
  2343.  
  2344.          +04:    A Word apparently reserved for use by TURBO.
  2345.  
  2346.          +06:    A Word apparently reserved for use by TURBO.
  2347.  
  2348.        One can determine the defining block for a Global VARiable declaration
  2349.        and our  program attempts  to do  just that.    A  by-product  of  the
  2350.        dictionary mapping  algorithm allows  the declaring  block to be found
  2351.        and its  qualified name  printed.   This information  is also  used to
  2352.        explain fix-up  data as  to its  source.   Results will  be incomplete
  2353.        unless a really comprehensive dictionary is present in the unit.  Such
  2354.        DSegs can  be referenced  by many  CSegs and  we only locate the first
  2355.        one.   This is  okay for  Pascal code but it's ambiguous for assembler
  2356.        since the names may be PUBLIC and referenced by more than one module.
  2357.  
  2358.  
  2359.  
  2360.        6.5 DLL LIST
  2361.  
  2362.  
  2363.        This list is present ONLY in Units compiled by the Windows Version and
  2364.        then only if the unit calls Dynamic Link Library (DLL) PROCS.  The DLL
  2365.        List has the following format:
  2366.  
  2367.          +00:    Four (4) bytes of binary zeroes (reserved for work?).
  2368.  
  2369.          +04:    A variable-sized  String that contains the name of the DLL
  2370.                  MEMBER name  or the PROC name (for DLL reference by NAME).
  2371.                  The string  is truncated  to actual  size as  usual for  a
  2372.                  unit.
  2373.  
  2374.        Procedures or Functions which reside in DLL's have entries in the PROC
  2375.        map but NOT in the CSeg Map since the executable code is external.
  2376.  
  2377.  
  2378.  
  2379.        6.6 DONOR UNIT LIST
  2380.  
  2381.  
  2382.        This list contains an entry for each Unit (taken from the "USES" list)
  2383.        which MAY  contribute either CODE or DATA to the executable file.  Not
  2384.        all units do make such a contribution as some exist merely to define a
  2385.        collection of  Types, etc.  A Unit gets into this list if there exists
  2386.        a single Fix-Up Data Entry that references CODE or DATA in that Unit.
  2387.  
  2388.        The list  is comprised  of elements  whose SIZE  is variable and whose
  2389.        format is as follows:
  2390.  
  2391.          +00:    A WORD apparently reserved for use by TURBO.
  2392.  
  2393.          +02:    A variable-length String containing the unit name.
  2394.  
  2395.  
  2396.  
  2397.  
  2398.  
  2399.  
  2400.        ──────────────────────────────────────────────────────────────────────
  2401.        June 6, 1991                                                   Page 38
  2402.  
  2403.  
  2404.  
  2405.                            Inside TURBO Pascal Unit Files            
  2406.        ──────────────────────────────────────────────────────────────────────
  2407.  
  2408.        6.7 SOURCE FILE LIST
  2409.  
  2410.  
  2411.        This list contains an entry for each "source" file used to compile the
  2412.        Unit.   This includes the Primary Pascal file, files containing Pascal
  2413.        code included  by means  of the  {$I filename.xxx} compiler directive,
  2414.        and .OBJ files included by the {$L filename.OBJ} compiler directive.
  2415.  
  2416.        The order  of entries  in this list is critical since it maps the CODE
  2417.        segments stored in the unit.  The order of the entries is as follows:
  2418.  
  2419.          The Primary Pascal file;
  2420.  
  2421.          All Included Pascal files;
  2422.  
  2423.          All Included .OBJ files.
  2424.  
  2425.        Mapping of CSegs to files is done as follows:
  2426.  
  2427.          Each .OBJ  file contributes  a SINGLE Code Segment (if any).  Note
  2428.                  that this  author has  not observed  an .OBJ  module  that
  2429.                  contains only  a DATA  Segment (but  that seems a distinct
  2430.                  possibility).
  2431.  
  2432.          The Primary  Pascal file  (augmented by all included Pascal Files)
  2433.                  contributes zero or more CODE Segments.
  2434.  
  2435.        Therefore, there  are at least as many CSeg entries as .OBJ files.  If
  2436.        more, then  the excess entries (those at the front of the list) belong
  2437.        to the Pascal files that make up the Pascal source for the unit.
  2438.  
  2439.        The format of an entry in this list is as follows:
  2440.  
  2441.          +00:    A flag byte that indicates the type of file represented;    
  2442.  
  2443.                  04h -> the Primary Pascal Source File,  
  2444.                  03h -> an Included Pascal Source File,  
  2445.                  05h -> an .OBJ file that contains a CODE segment  
  2446.                  06h -> an .RES file from {$R xxx.RES} (Windows RESOURCE).
  2447.  
  2448.          +01:    A Word apparently reserved for use by the Compiler/Linker.
  2449.  
  2450.          +03:    A Word  that is zero for .OBJ files and which contains the
  2451.                  file directory time-stamp for Pascal Files.
  2452.  
  2453.          +05:    A Word  that is zero for .OBJ files and which contains the
  2454.                  file directory date-stamp for Pascal Files.
  2455.  
  2456.          +07:    A  variable-sized   string  containing  the  filename  and
  2457.                  extension of the file used during compilation.
  2458.  
  2459.  
  2460.  
  2461.  
  2462.  
  2463.  
  2464.        ──────────────────────────────────────────────────────────────────────
  2465.        June 6, 1991                                                   Page 39
  2466.  
  2467.  
  2468.  
  2469.                            Inside TURBO Pascal Unit Files            
  2470.        ──────────────────────────────────────────────────────────────────────
  2471.  
  2472.        6.8 DEBUG TRACE TABLE
  2473.  
  2474.  
  2475.        If Debug  support was  selected at  compile time, then all Pascal code
  2476.        which supports  Debugging produces  an entry in this table.  The table
  2477.        entries themselves are variable in size and have the following format:
  2478.  
  2479.          +00:    A Word  which contains  an LL  that locates  the Directory
  2480.                  Header of the Symbol (a PROC name) this entry represents.
  2481.  
  2482.          +02:    A Word  which contains  the offset (within the Source File
  2483.                  List) of  the entry that names the file that generated the
  2484.                  CSeg being traced.  This allows the file included by means
  2485.                  of the  {$I filename} directive to be identified for DEBUG
  2486.                  purposes, as well as code produced from the Primary File.
  2487.  
  2488.          +04:    A Word containing the number of bytes of data that precede
  2489.                  the BEGIN statement code in the segment.  For Pascal PROCS
  2490.                  these  bytes   consist  of   literal  constants,  un-typed
  2491.                  constants, and  other data  such as range-checking limits,
  2492.                  etc.
  2493.  
  2494.          +06:    A Word  containing the  Line Number of the BEGIN statement
  2495.                  for the PROC.
  2496.  
  2497.          +08:    A Word  containing the  number of  lines of Source Code to
  2498.                  Trace in this Segment.
  2499.  
  2500.          +0A:    An array  of bytes  whose size   is at least the number of
  2501.                  source code  lines in  the PROC.   Each  byte contains the
  2502.                  number of bytes of object code in the corresponding source
  2503.                  line.   This appears to be an array of SHORTINT since if a
  2504.                  "line" contains more than 127 bytes, then a single byte of
  2505.                  $80 precedes  the actual  byte count as a sort of "escape"
  2506.                  and the  next byte  records the  up to  255 bytes  for the
  2507.                  line.  This situation has not yet been fully explored.  We
  2508.                  do not  yet know  what happens  in the  event  a  line  is
  2509.                  credited with spawning more than 255 bytes of code.
  2510.  
  2511.  
  2512.  
  2513.        7. CODE, DATA, FIX-UP INFO
  2514.  
  2515.  
  2516.        This area  begins at the start of the next free PARAGRAPH.  This means
  2517.        that its  offset from  the beginning  of the  Unit ALWAYS  ends in the
  2518.        digit zero.
  2519.  
  2520.        This area  contains the  CODE segments,  CONST DATA  segments, and the
  2521.        Relocation (Fix-Up) Data required for linking.
  2522.  
  2523.  
  2524.  
  2525.  
  2526.  
  2527.  
  2528.        ──────────────────────────────────────────────────────────────────────
  2529.        June 6, 1991                                                   Page 40
  2530.  
  2531.  
  2532.  
  2533.                            Inside TURBO Pascal Unit Files            
  2534.        ──────────────────────────────────────────────────────────────────────
  2535.  
  2536.        7.1 OBJECT CSEGS
  2537.  
  2538.  
  2539.        Each CODE  segment included  in the  unit appears here as specified by
  2540.        the CSeg  Map Table.  Depending on usage, these segments may appear in
  2541.        the executable file.  There are no filler bytes between segments.
  2542.  
  2543.  
  2544.  
  2545.        7.2 CONST DSEGS
  2546.  
  2547.  
  2548.        This section begins at the start of the first free PARAGRAPH following
  2549.        the end  of the  Object CSegs.   This  means that  its offset from the
  2550.        beginning of the Unit ALWAYS ends in the digit zero.
  2551.  
  2552.        A DATA  segment fragment  appears here  for each  CSeg that declares a
  2553.        typed constant,  and for  each OBJECT  which employs  Virtual Methods,
  2554.        Constructors or  Destructors.   There  are  no  filler  bytes  between
  2555.        segments.
  2556.  
  2557.        If local symbols were generated, there is always enough information to
  2558.        allow documenting the scope of the declaration as well as interpreting
  2559.        the data  in the display since the needed type declarations would also
  2560.        be available.  Our program merely identifies the defining block.
  2561.  
  2562.  
  2563.  
  2564.  
  2565.  
  2566.  
  2567.  
  2568.  
  2569.  
  2570.  
  2571.  
  2572.  
  2573.  
  2574.  
  2575.  
  2576.  
  2577.  
  2578.  
  2579.  
  2580.  
  2581.  
  2582.  
  2583.  
  2584.  
  2585.  
  2586.  
  2587.  
  2588.  
  2589.  
  2590.  
  2591.  
  2592.        ──────────────────────────────────────────────────────────────────────
  2593.        June 6, 1991                                                   Page 41
  2594.  
  2595.  
  2596.  
  2597.                            Inside TURBO Pascal Unit Files            
  2598.        ──────────────────────────────────────────────────────────────────────
  2599.  
  2600.        7.3 FIX-UP DATA TABLES
  2601.  
  2602.  
  2603.        There are  - at  most - two Fix-Up Data Tables in any given .TPU file.
  2604.        The first  is for  the CODE  Area and the second is for the CONST DSeg
  2605.        area.   Both are  paragraph aligned  and both have size information in
  2606.        the unit header.
  2607.  
  2608.        Turbo Pascal  for DOS  and Turbo Pascal for Windows apparently utilize
  2609.        differing code-generation  models where  floating-point is  concerned.
  2610.        The nub of the difference appears to lie in emulation support.  In the
  2611.        DOS product,  the 8087 emulator is included in the SYSTEM unit while a
  2612.        WINDOWS DLL  (WIN87EM) furnishes  floating-point emulation support for
  2613.        applications.  This seems to be the reason for a new fix-up format and
  2614.        for the way floating-point options are presented in TP for Windows.
  2615.  
  2616.        The Table  consists of an array of eight (8) byte entries whose format
  2617.        is as follows:
  2618.  
  2619.          +00:    A Byte containing the offset within the Donor Unit List of
  2620.                  the Unit  name that this entry refers to.  This can be the
  2621.                  compiled Unit or some previously compiled external unit.
  2622.  
  2623.          +01:    A Byte of BIT switches that identify the type of reference
  2624.                  and the  size of the needed fix-up (WORD or DWORD).  A lot
  2625.                  of guess-work led to the following interpretation:
  2626.  
  2627.                  7654  (bits 3-0 don't seem to be used)
  2628.  
  2629.                  00--  Locate item via a PROC Map,
  2630.                  01--  Locate item via a CSeg Map,
  2631.                  10--  Locate item via a Global VAR DSeg Map,
  2632.                  11--  Locate item via a Const DSeg Map,
  2633.                  --00  WORD offset has NO effective address adjustment,
  2634.                  --01  WORD offset HAS an effective address adjustment,
  2635.                  --10  WORD SEGMENT-Only fix-up (address of some PUBLIC
  2636.                        segment),
  2637.                  --11  DWORD (FAR) pointer; possible effective address
  2638.                        adjustment.
  2639.  
  2640.          +02:    A  Word   containing  the  offset  within  the  Map  table
  2641.                  referenced according to the above code scheme.
  2642.  
  2643.          +04:    A Word  containing an  offset within  the  target  segment
  2644.                  which will  be  added  to  the  effective  address.    For
  2645.                  example, a  reference to  the VAR  DSeg Map will require a
  2646.                  final offset to locate the item (variable) within the DATA
  2647.                  SEGMENT being  referenced here.   This  may also be needed
  2648.                  for references to LITERAL DATA embedded in a CODE SEGMENT.
  2649.  
  2650.          +06:    A Word  containing the  offset within  the  CODE  or  DATA
  2651.                  segment owning  this entry  that contains  the area  to be
  2652.                  patched with the value of the final effective address.
  2653.  
  2654.  
  2655.  
  2656.        ──────────────────────────────────────────────────────────────────────
  2657.        June 6, 1991                                                   Page 42
  2658.  
  2659.  
  2660.  
  2661.                            Inside TURBO Pascal Unit Files            
  2662.        ──────────────────────────────────────────────────────────────────────
  2663.  
  2664.        In the  WINDOWS environment,  an additional  format is possible and it
  2665.        has the following appearance:
  2666.  
  2667.          +00:    A Word containing $FFFF which appears to serve as a format
  2668.                  identifier.
  2669.  
  2670.          +02:    A Word  containing an  Emulator Fix-Up  type code.   After
  2671.                  looking at  many such  entries in  context with the object
  2672.                  code, the following scheme seems to be operative:
  2673.  
  2674.              2-> target floating point op has SS: override prefix;
  2675.              3-> target floating point op has CS: override prefix;
  2676.              4-> target floating point op has ES: override prefix;
  2677.              5-> target floating point op has NO override prefix;
  2678.              6-> target floating point op is "FWAIT" ($909B).
  2679.  
  2680.  
  2681.          +04:    A Word that is probably always zero.
  2682.  
  2683.          +06:    Offset to  the floating-point  operation to  be  emulated.
  2684.                  This operation  is always  prefixed with  a WAIT  op ($9B)
  2685.                  unless it  is an FWAIT ($909B).  If an operation is not so
  2686.                  prefixed, then no fix-up record is generated for it.
  2687.  
  2688.        These latter  fix-up records are (probably) incorporated into the .EXE
  2689.        file (following  suitable transformations)  so that the Windows Loader
  2690.        can see  and process  them.   Presumably, they are simply ignored if a
  2691.        co-processor chip  is present  and working.   If  not, they  tell  the
  2692.        loader where the emulated instructions are.  What the loader does with
  2693.        this information  is pure  guess-work but  it probably works something
  2694.        like this:
  2695.  
  2696.          1)      if the  Emulator Type  code in  the word  at +02 indicates
  2697.                  that a  segment override  prefix is  present (codes 2..4),
  2698.                  replace the  first three bytes of the instruction with the
  2699.                  following:
  2700.  
  2701.                  $CD $3C "xxyyyyyy" where "yyyyyy" is the least-significant
  2702.                  six bits  of the  "escape" byte  (originally $D8..$DF) and
  2703.                  "xx"  is   the  ones-complement  of  the  two-bit  segment
  2704.                  register value (00=ES, 01=CS,10=SS,11=DS).
  2705.  
  2706.                  This method  would result  in replacement  of the  WAIT op
  2707.                  ($9B), the  segment override prefix, and the "escape" byte
  2708.                  with the  above string  at program  load time.  This would
  2709.                  allow an application to run regardless of the availability
  2710.                  of co-processor support
  2711.  
  2712.          2)      if the  Emulator Type  code in  the word at +02 is 5, then
  2713.                  there is  no override prefix.  Replace the first two bytes
  2714.                  of the instruction with the following:
  2715.  
  2716.                  $CB $jj  (where "jj"  is "escape"  - $A4).   $jj  is  then
  2717.                  chosen from the range $34..$3B.
  2718.  
  2719.  
  2720.        ──────────────────────────────────────────────────────────────────────
  2721.        June 6, 1991                                                   Page 43
  2722.  
  2723.  
  2724.  
  2725.                            Inside TURBO Pascal Unit Files            
  2726.        ──────────────────────────────────────────────────────────────────────
  2727.  
  2728.          3)      if the  Emulator Type  code in  the word at +02 is 6, then
  2729.                  the operation  to emulate  is FWAIT.   Replace the $90 $9B
  2730.                  with $CB $3D.
  2731.  
  2732.        Since $CB is the op-code for INT then, if emulation were in effect, we
  2733.        would produce  INT $34-$3D  whenever a  floating-point  operation  was
  2734.        found that could be emulated.
  2735.  
  2736.        This approach  has the  advantage that  we don't  have  to  commit  to
  2737.        emulation or  non-emulation at  compile-time.  Rather, the decision is
  2738.        made at load time and is transparent to the user.  It's interesting to
  2739.        note that the DOS compiler generates such code without benefit of fix-
  2740.        ups whenever  both 8087  and emulation  support are  elected since the
  2741.        emulator is  a component  of the  SYSTEM unit  in DOS.  In WINDOWS, we
  2742.        merely include a reference to WIN87EM plus the above fix-ups.
  2743.  
  2744.        The technique  relies on  the  fact  that  8087  ops  are  necessarily
  2745.        prefixed by  the WAIT  byte (except  for the  "FN..." variants).  This
  2746.        provides sufficient  space to replace as above in-situ.  This approach
  2747.        WILL NOT work if the code contains floating-point instructions without
  2748.        a WAIT  prefix byte.  If the object code requires an 80287 or an 80387
  2749.        (for example), then it would seem that that Interrupt 07H will have to
  2750.        be serviced  by WIN87EM.   This  is all guess-work for now.  I haven't
  2751.        seen any literature documenting WIN87EM techniques.
  2752.  
  2753.  
  2754.  
  2755.  
  2756.  
  2757.  
  2758.  
  2759.  
  2760.  
  2761.  
  2762.  
  2763.  
  2764.  
  2765.  
  2766.  
  2767.  
  2768.  
  2769.  
  2770.  
  2771.  
  2772.  
  2773.  
  2774.  
  2775.  
  2776.  
  2777.  
  2778.  
  2779.  
  2780.  
  2781.  
  2782.  
  2783.  
  2784.        ──────────────────────────────────────────────────────────────────────
  2785.        June 6, 1991                                                   Page 44
  2786.  
  2787.  
  2788.  
  2789.                            Inside TURBO Pascal Unit Files            
  2790.        ──────────────────────────────────────────────────────────────────────
  2791.  
  2792.        8. SUPPLIED PROGRAM
  2793.  
  2794.  
  2795.        In order that the above information be made constructively useful, the
  2796.        author has designed a program that automates the process of discovery.
  2797.        It is  not a work of art but it does give useful results provided your
  2798.        PC has enough available memory.
  2799.  
  2800.        The program  source code  has been re-organized many times as I simply
  2801.        haven't been  able resist  tinkering with  it.   Minor changes  in its
  2802.        output have been implemented to enhance its usefulness.
  2803.  
  2804.        It should  be obvious  that the  program was  not designed "top-down".
  2805.        Rather, it  just evolved as each new discovery was made.  Later on, it
  2806.        seemed reasonable to try to document some of the relations between the
  2807.        various lists  and tables  and the program tries to make some of these
  2808.        relations clear, albeit with varying degrees of success.
  2809.  
  2810.        It may  not be  obvious to  all readers,  but the  program is actually
  2811.        fighting a  losing battle  in many  respects.  The ".TPU" file was not
  2812.        designed with  the intent  of enabling  de-compilation, disassembly or
  2813.        de-linking.   Thus, some  interesting  semantic  information  is  lost
  2814.        forever since  it's not  needed for  either compilation  or debugging.
  2815.        For example,  it  doesn't  seem  to  be  possible  to  determine  with
  2816.        certainty the  source file  for a  CONST DSeg or GLOBAL VAR DSeg where
  2817.        ".OBJ" files  are linked  into the  ".TPU" file.  Of course, it MAY be
  2818.        possible in  certain cases but, in general, there is simply not enough
  2819.        information available to definitely determine the source.  This is due
  2820.        to the  fact that one ".OBJ" file may define such a DSeg and contain a
  2821.        CSeg that  refers to  it but,  if the  DSeg is  PUBLIC, it may also be
  2822.        referred to  by other  CSegs.   Each  of  the  CSegs  that  make  such
  2823.        references to the DSeg view it as an EXTERNAL as far as fix-up data is
  2824.        concerned.   Therefore, it's  impossible to  determine  which  of  the
  2825.        referencing CSegs was drawn from the same ".OBJ" file as the DSeg.
  2826.  
  2827.  
  2828.  
  2829.        8.1 TWU1
  2830.  
  2831.  
  2832.        This is  the main program.  It will ask for the name of the unit to be
  2833.        documented.   Reply with  the unit name only.  The program will append
  2834.        the ".TPU"  extension and  will search  for the  proper file.  It will
  2835.        also search the appropriate library file; if necessary.
  2836.  
  2837.        The program  will then  ask if  the unit  is a DOS or WINDOWS unit and
  2838.        will require  a "w" or "d" answer.  This determines which unit library
  2839.        file to  search (TURBO.TPL  or TPW.TPL)  for the  SYSTEM  unit  (among
  2840.        others).
  2841.  
  2842.        The program  will then ask if Dis-Assembly is desired and will require
  2843.        a "y" or "n" answer.  If "y", it also asks about the CPU.
  2844.  
  2845.  
  2846.  
  2847.  
  2848.        ──────────────────────────────────────────────────────────────────────
  2849.        June 6, 1991                                                   Page 45
  2850.  
  2851.  
  2852.  
  2853.                            Inside TURBO Pascal Unit Files            
  2854.        ──────────────────────────────────────────────────────────────────────
  2855.  
  2856.        The  current  directory  will  be  searched  first,  followed  by  all
  2857.        directories in  the current  PATH.  If the .TPU file is not found, the
  2858.        program will  search for  it in  the "TURBO.TPL"  or in  the "TPW.TPL"
  2859.        (Turbo Pascal  Library) file  as appropriate.   Units  in  the  "USES"
  2860.        list(s) will also be loaded to enable resolution of LG items.
  2861.  
  2862.        If the  desired unit  is found, the program will write a report to the
  2863.        current directory  named "unitname.lst"  which contains  its analysis.
  2864.        The format of the report is such that it may be copied to a printer if
  2865.        that printer supports TTY control codes with form-feeds.  Be judicious
  2866.        in doing  this however  since there can be a lot of information.  Some
  2867.        of the  units supplied  by Borland  can produce  almost 2 MB of report
  2868.        output, depending  on whether  it's Version 6.0 for DOS or Version 1.0
  2869.        for Windows (some supplied Windows Units are BIG).
  2870.  
  2871.  
  2872.  
  2873.        8.1.1 UNIT TWU1EQU
  2874.  
  2875.  
  2876.        This Unit  contains constants, types and procedures of general utility
  2877.        that are  not strictly  unit or I/O related.  One of the more powerful
  2878.        procedures is a general-purpose QuickSort procedure.
  2879.  
  2880.        It also  contains a  Heap Error Function that keeps track of the high-
  2881.        water mark  of Heap  Utilization of  any program  that uses  it.  This
  2882.        function gets installed automatically.
  2883.  
  2884.        This Unit makes SOME use of the INLINE assembler for speed and not out
  2885.        of sheer necessity.  Some of the routines are INLINE Macros to provide
  2886.        for short expansions of otherwise overhead-ridden facilities.
  2887.  
  2888.  
  2889.  
  2890.        8.1.2 UNIT TWU1RPT
  2891.  
  2892.  
  2893.        This is a Unit that contains the text-file output routines required by
  2894.        the main  program.   This relieves  the main  program of  some of  the
  2895.        tedium of handling report formatting and pagination issues.
  2896.  
  2897.  
  2898.  
  2899.        8.1.3 UNIT TWU1UAM
  2900.  
  2901.  
  2902.        This Unit  contains all  Type Definitions,  Structures, and  primitive
  2903.        Functions and  Procedures required  by the  program  for  ".TPU"  file
  2904.        acquisition and  analysis.   All structures  documented in this report
  2905.        are also  documented in  the interface by means of the TYPE mechanism.
  2906.        Some of the structures are difficult if not impossible to define using
  2907.        ISO Pascal  but Turbo  Pascal provides  the means  for getting the job
  2908.        done.
  2909.  
  2910.  
  2911.  
  2912.        ──────────────────────────────────────────────────────────────────────
  2913.        June 6, 1991                                                   Page 46
  2914.  
  2915.  
  2916.  
  2917.                            Inside TURBO Pascal Unit Files            
  2918.        ──────────────────────────────────────────────────────────────────────
  2919.  
  2920.        Some algorithms  have been  cast with  object-orientation in  mind and
  2921.        have potential  for re-use  in other  contexts.   The unit  computes a
  2922.        cover for the dictionary and deduces relationships between dictionary,
  2923.        code, data  and the  CSeg, PROC,  CONST  and  VAR  Maps  discussed  in
  2924.        Sections 6.1  through 6.4  on  Pages  35..37.    This  information  is
  2925.        retrieved by the main program to drive the printing process.
  2926.  
  2927.        This Unit also loads all units specified in the USES list of the prime
  2928.        unit to allow the names of externally defined types to be recovered on
  2929.        the report.   Array  bounds are  also retrieved in this way.  The code
  2930.        will search  for needed units in appropriate unit library file without
  2931.        intervention.   Close attention is paid to Heap Management and minimal
  2932.        utilization of  Heap storage.   The  dictionary  areas  of  the  Units
  2933.        located in  the USES list get loaded into the Heap at no extra charge.
  2934.        Nothing but the dictionary area is of any use at this point.  The name
  2935.        and fully-qualified  file name  of each  unit successfully  loaded are
  2936.        printed at the top of the listing.  Unit version numbers must agree or
  2937.        the unit  will not be loaded.  Dictionary covers are computed for each
  2938.        loaded unit to aid in rapid LG-resolution.
  2939.  
  2940.        Lack of sufficient Heap Storage will not necessarily cause the program
  2941.        to fail.   Heap  Space MUST  be available to load the primary unit and
  2942.        perform the  necessary analyses, but the secondary or nested units are
  2943.        not essential.   If  they cannot  be  loaded,  you  merely  lose  some
  2944.        descriptive information.  If Heap exhaustion occurs at a critical step
  2945.        however, the program will generate RunError 215.
  2946.  
  2947.  
  2948.  
  2949.        8.1.4 UNIT TWU1UNA
  2950.  
  2951.  
  2952.        This unit is a rudimentary disassembler.  The output will not assemble
  2953.        and may  look strange  to a "real" assembler programmer since I am not
  2954.        well-qualified in this area.  However, the basis for support of 80286,
  2955.        80386 etc.  processors is  present as well as coprocessor support.  Of
  2956.        perhaps the  greatest interest  is that  it does  appear to decode the
  2957.        emulated coprocessor  instructions that  are implemented via INT 34-3D
  2958.        in the MS-DOS versions of Turbo Pascal.
  2959.  
  2960.        Be warned  however.  The output is not guaranteed since this was coded
  2961.        by myself  and I  am perhaps  the rankest amateur that ever approached
  2962.        this quite  awful assembler  language.   For convenience,  the operand
  2963.        coding mimics TASM "Ideal" mode.
  2964.  
  2965.        As is  usual with programs of this type, error-recovery is minimal and
  2966.        no context  checking is  performed.  If the operation code is found to
  2967.        be valid,  then a  valid instruction  is assumed  -- even  if  invalid
  2968.        operands are present.
  2969.  
  2970.        The only positives that apply to this program are that it doesn't slow
  2971.        the cpu down (although a lot more output is produced), and it does let
  2972.        one "tune" code for compactness by letting one view the results of the
  2973.        coding directly.   Also,  incomplete instructions  are handled as data
  2974.        rather than overrunning into the next proc.
  2975.  
  2976.        ──────────────────────────────────────────────────────────────────────
  2977.        June 6, 1991                                                   Page 47
  2978.  
  2979.  
  2980.  
  2981.                            Inside TURBO Pascal Unit Files            
  2982.        ──────────────────────────────────────────────────────────────────────
  2983.  
  2984.        8.2 NOTES ON PROGRAM LOGIC
  2985.  
  2986.  
  2987.        The following  sections discuss  a few  of the methods employed by the
  2988.        supplied program.  There are no cutting-edge algorithms here.  Results
  2989.        counted for a lot more than technique.
  2990.  
  2991.  
  2992.  
  2993.        8.2.1 FORMATTING THE DICTIONARY
  2994.  
  2995.  
  2996.        Printing the unit dictionary area in a way that exposes its underlying
  2997.        semantics is  no small  task.   The unit  dictionary area  itself is a
  2998.        rather amorphous-looking  mass of  data composed  of hash tables, Name
  2999.        Entries and  stubs, type  descriptors, etc.   In  order to present all
  3000.        this information  in a meaningful way, we have to reveal its structure
  3001.        and this  cannot be  done by means of a sequential "browse" technique.
  3002.        Rather, we have to visit all nodes in the dictionary area so that each
  3003.        may be  formatted in  a way  that exposes  their function and meaning.
  3004.        This is  made necessary  by the  fact that  items  are  added  to  the
  3005.        dictionary as  encountered and  no convenient  ordering of entry types
  3006.        exists.  What we have here is the problem of finding a minimal "cover"
  3007.        for  the  dictionary  area  that  properly  exposes  the  content  and
  3008.        structure of the dictionary area.
  3009.  
  3010.        To do this, we scan the dictionary recursively to determine the number
  3011.        of structures  that we  need to map.  Then we get heap storage for the
  3012.        array of records that will hold the mapping information and repeat our
  3013.        recursive dictionary scan, this time constructing the mapping records.
  3014.  
  3015.        The recursive  algorithm is "delicate" in that it is vulnerable to the
  3016.        cycles that  our analysis  uncovers -  particularly  when  polymorphic
  3017.        objects are involved.  Therefore, we have incorporated a simple little
  3018.        trap that  tries to  discover such  cycles and  avoid  them.    It  is
  3019.        possible that  the algorithm  could fail for exceedingly complex units
  3020.        but it handles the worst cases from Borland with ease.  Prior versions
  3021.        of this unit accomplished this task without recursion but required too
  3022.        many tricky pointer manipulations that were environmentally sensitive,
  3023.        so recursion  was adopted.   Since  unit dictionaries don't tend to be
  3024.        deeply nested,  we get reasonable heap utilization coupled with stable
  3025.        algorithms.
  3026.  
  3027.        The result  is an array containing one entry for each structure in the
  3028.        unit dictionary  area that  is identifiable via traversal.  Each entry
  3029.        in the  array contains  information about nesting level, parent scope,
  3030.        structure  type  and  location.    The  array  thus  forms  a  set  of
  3031.        descriptors that  drive the  process of formatting the dictionary area
  3032.        for display.   The process may be likened to "painting by the numbers"
  3033.        or to  finding a  way to  lay tile  on a  flat surface  using tiles of
  3034.        differing shapes until the floor is exactly covered.
  3035.  
  3036.  
  3037.  
  3038.  
  3039.  
  3040.        ──────────────────────────────────────────────────────────────────────
  3041.        June 6, 1991                                                   Page 48
  3042.  
  3043.  
  3044.  
  3045.                            Inside TURBO Pascal Unit Files            
  3046.        ──────────────────────────────────────────────────────────────────────
  3047.  
  3048.        There is  one significant limitation that needs to be pointed out.  It
  3049.        is not  always possible to determine the "parent" or "owner" of a node
  3050.        with certainty.   The  following discussion illustrates the problem of
  3051.        finding the "real" parent of a Type Descriptor.
  3052.  
  3053.        Almost every "type" in Turbo Pascal is actually derived from the basic
  3054.        types that  are defined  in the  SYSTEM.TPU unit  --  e.g.  "INTEGER",
  3055.        "BYTE", etc.   In  addition, several  of the  Type Descriptors  in the
  3056.        SYSTEM unit are referenced by more than one Name Entry.  Thus, we find
  3057.        that a  "many-to-one" relationship  may exist between Name Entries and
  3058.        Type Descriptors.   How  does one  find out  which is  the entry  that
  3059.        actually gave rise to the Type Descriptor?
  3060.  
  3061.        The Dictionary  Area of  a unit  has some  special properties,  one of
  3062.        which is  the fact  that the  Name Entries  for named  Types are often
  3063.        located quite  near their  primary type  descriptors.   The Dictionary
  3064.        Area seems  to be  treated as  an upward growing heap with the various
  3065.        structures being  added by Turbo as encountered.  This makes it likely
  3066.        that the  Type "Q"  header which  gives rise  to a  type descriptor is
  3067.        quite likely  to occur  earlier in  the Dictionary Area than any other
  3068.        entry which  refers to  the same  descriptor.  We use this property to
  3069.        allocate "ownership"  but it  may not  be  "fool-proof".    Some  type
  3070.        descriptors are  spawned by  other type  descriptors,  especially  for
  3071.        structured  types.     Further,   structured  named  types  are  often
  3072.        accompanied by pointer types and this results in having multiple named
  3073.        types sharing  the same type descriptor.  We don't attempt to allocate
  3074.        "ownership" to  "spawned" type descriptors but we do try to keep track
  3075.        of scope information.
  3076.  
  3077.        A useful  by-product of  the above  process is the ability to discover
  3078.        many of  the associations  between Global  Variables,  Typed  CONST's,
  3079.        VMT's and the blocks in which they are declared or defined.
  3080.  
  3081.  
  3082.  
  3083.        8.2.2 THE DISASSEMBLER
  3084.  
  3085.  
  3086.        To start with, I apologize up front for mistakes which are bound to be
  3087.        present in  this routine.   I  am not really a MASM or TASM programmer
  3088.        and I will not pretend otherwise.  This being the case, the formatting
  3089.        I have  chosen for  the operands  may be  erroneous or  misleading and
  3090.        might (if  submitted to  one of  the "real" assemblers) produce object
  3091.        code quite different from what is expected.  I hope not, but I have to
  3092.        admit it's possible.
  3093.  
  3094.  
  3095.  
  3096.  
  3097.  
  3098.  
  3099.  
  3100.  
  3101.  
  3102.  
  3103.  
  3104.        ──────────────────────────────────────────────────────────────────────
  3105.        June 6, 1991                                                   Page 49
  3106.  
  3107.  
  3108.  
  3109.                            Inside TURBO Pascal Unit Files            
  3110.        ──────────────────────────────────────────────────────────────────────
  3111.  
  3112.        My intention  in adding this unit was to support hand-tuning of object
  3113.        code.   With practice  and some  effort, one can observe the effect on
  3114.        the object  module caused  by specific  Pascal coding.    Thus,  where
  3115.        compactness or  speed is an issue of paramount importance, disassembly
  3116.        can be  of help.   In some cases, a simple re-arrangement of the local
  3117.        variable declarations  in a procedure can have a significant effect on
  3118.        the size  of the  code if it means the difference between 1 and 2-byte
  3119.        displacements for  each instruction  that references  a specific local
  3120.        variable.   Potential  applications  along  these  lines  seem  almost
  3121.        unlimited.
  3122.  
  3123.        I adopted an operand format not unlike that of TASM "Ideal" mode since
  3124.        it was  more convenient  to do  so and  looked more readable to me.  I
  3125.        relied on  several reference books for guidance in decoding the entire
  3126.        mess and  I found  that there were several flaws (read ERRORS) in some
  3127.        of them  which made  the  job  that  much  more  difficult.    I  then
  3128.        compounded my  problems by  attempting to  handle 80386  specific code
  3129.        even though  Turbo Pascal does not yet generate code specific to these
  3130.        processors.   I simply  felt that  the effort  involved in writing any
  3131.        sort of Dis-Assembly program for Turbo Pascal units was an effort best
  3132.        experienced not  more than  once.  With all this self-flagellation out
  3133.        of my  system once  and for all, I will try to show the basic strategy
  3134.        of the  program and  to  explain  the  limitations  and  some  of  the
  3135.        discoveries I made.
  3136.  
  3137.        The routine  is intended  to be  idiotically simple - i.e., no smarter
  3138.        than the  DEBUG command  in principle.   The basic idea is:  pass some
  3139.        text to  the routine and get back ONE line derived from some prefix of
  3140.        that text.   Repeat  as necessary until all text is gone.  Thus, there
  3141.        is no attempt to check the context of the text being processed.  Also,
  3142.        some configurations  of the  "modR/M" byte  may invalid  for  selected
  3143.        instructions.  I don't try to screen these out since the intent was to
  3144.        look at  the presumably  correct code  produced by TURBO Pascal -- not
  3145.        devious assembly language.  Also, this program regards WAIT operations
  3146.        as "stand-alone"  -- i.e.,  it doesn't  check to  see if a coprocessor
  3147.        operation follows for which the WAIT might be regarded as a prefix.
  3148.  
  3149.        One area  of real  difficulty  was  figuring  out  the  Floating-Point
  3150.        emulations  used  by  Turbo  Pascal  Version  6.0  for  DOS  that  are
  3151.        implemented by means of interrupts $34 through $3D.  I don't know if I
  3152.        got it  right, but the results seem reasonable and consistent.  In the
  3153.        listing, the  Interrupt is  produced on  one  line,  followed  by  its
  3154.        parameters on  the next line.  The parameter line is given the op-code
  3155.        "EMU_xxxx" where  "xxxx" is  the coprocessor  op-code I felt was being
  3156.        emulated.   Interrupt $3C was a real puzzler but after seeing a lot of
  3157.        code in  context, I think that the segment override is communicated to
  3158.        the emulator by means of the first byte after the $3C.
  3159.  
  3160.  
  3161.  
  3162.  
  3163.  
  3164.  
  3165.  
  3166.  
  3167.  
  3168.        ──────────────────────────────────────────────────────────────────────
  3169.        June 6, 1991                                                   Page 50
  3170.  
  3171.  
  3172.  
  3173.                            Inside TURBO Pascal Unit Files            
  3174.        ──────────────────────────────────────────────────────────────────────
  3175.  
  3176.        Normally, in  a non-emulator  environment, all  coprocessor operations
  3177.        (ignoring any  WAIT prefixes)  begin with  $D8-$DF.  What Borland (and
  3178.        maybe Microsoft)  seem to  have done  here is to change the $D8-$DF so
  3179.        that bits  7 and 6 of this byte are replaced with the one's complement
  3180.        of  the   2-bit  segment   register  number   found  in  various  8086
  3181.        instructions.  This seems to be how an override for the DS register is
  3182.        passed to  the emulator.    I  don't  KNOW  this  to  be  the  correct
  3183.        interpretation, but  the code I have examined in context seems to work
  3184.        under this  scheme, so  the disassembler  uses  it  to  interpret  the
  3185.        operand accordingly.
  3186.  
  3187.        For  80x86   machines,  the   problem  was   somewhat  simpler.    The
  3188.        disassembler takes a quick look at the first byte of the text.  Almost
  3189.        any byte  is valid  as the  initial byte  of an  instruction, but some
  3190.        instructions require more than one byte to hold the complete operation
  3191.        code.   Thus, step  1 classifies  bytes in  several ways  that lead to
  3192.        efficient recognition of valid operation codes.
  3193.  
  3194.        Once the  instruction has  been identified  in this way, it is more or
  3195.        less easy  to link  to supplemental  information that provides operand
  3196.        editing guidance, etc.
  3197.  
  3198.        The tables  that embody  the recognition scheme were constructed using
  3199.        PARADOX (another fine Borland product) and suitably coded queries were
  3200.        used to generate the actual Turbo Pascal code for compilation.
  3201.  
  3202.        For those  that are interested, the disassembler supports the address-
  3203.        size and operand-size prefixes of the 80386 as well as 32-bit operands
  3204.        and addresses  but remember  that Turbo Pascal doesn't generate these.
  3205.        A trivial  change is  provided for which allows segments which default
  3206.        to 32-bit mode to be handled as well.
  3207.  
  3208.        There is  a simple  mode variable that gets passed to the disassembler
  3209.        by its caller which specifies the most-capable processor whose code is
  3210.        to be  handled.   Codes are  provided for the 8086 (8088 is the same),
  3211.        80186 (same  as 80286  without  protected  mode  instructions),  80286
  3212.        (80186 plus  protected mode),  and 80386.  You now get asked which one
  3213.        to use.
  3214.  
  3215.        No such  specifier is provided for coprocessor support.  What is there
  3216.        is what  I think an 80387 supports.  I don't think that this is really
  3217.        a problem  if you  don't try to use this disassembler for anything but
  3218.        Turbo Pascal code.
  3219.  
  3220.        Error recovery is predictably simple.  The initial text byte is output
  3221.        as the  operand of a DB pseudo-op and provision is made to resume work
  3222.        at the next byte of text.
  3223.  
  3224.        I hope  this program  is found  to be useful in spite of the errors it
  3225.        must surely  contain.   I have yet to make much sense of the rules for
  3226.        MASM or  TASM operand  coding and I found very little of value in many
  3227.        of the  so-called "texts"  on the  subject.   I found  myself  in  the
  3228.        position of  that legendary  American in  England watching  a  Cricket
  3229.        match for the first time ("You mean it has RULES?").
  3230.  
  3231.  
  3232.        ──────────────────────────────────────────────────────────────────────
  3233.        June 6, 1991                                                   Page 51
  3234.  
  3235.  
  3236.  
  3237.                            Inside TURBO Pascal Unit Files            
  3238.        ──────────────────────────────────────────────────────────────────────
  3239.  
  3240.        9. UNIT LIBRARIES
  3241.  
  3242.  
  3243.        I have  examined .TPL  files in  and conclude  that their structure is
  3244.        trivial.   It's so  easy to handle them that the program now routinely
  3245.        examines either the TURBO.TPL or the TPW.TPL to resolve named types.
  3246.  
  3247.  
  3248.  
  3249.        9.1 LIBRARY STRUCTURE
  3250.  
  3251.  
  3252.        A Turbo  Pascal Library  (.TPL) file  is a  simple catenation of Turbo
  3253.        Pascal Unit  (.TPU) files.  Since the size of a Unit may be determined
  3254.        from the  Unit Header  (see Section 4.2, Page 16), it is simple to see
  3255.        that one may "browse" through a .TPL file looking for an external unit
  3256.        such as  SYSTEM.TPU.   The supplied program does just that in its unit
  3257.        retrieval process  so the  TPUMOVER utility  is no longer required for
  3258.        processing of units in either the TURBO.TPL or in the TPW.TPL file.
  3259.  
  3260.  
  3261.  
  3262.  
  3263.  
  3264.  
  3265.  
  3266.  
  3267.  
  3268.  
  3269.  
  3270.  
  3271.  
  3272.  
  3273.  
  3274.  
  3275.  
  3276.  
  3277.  
  3278.  
  3279.  
  3280.  
  3281.  
  3282.  
  3283.  
  3284.  
  3285.  
  3286.  
  3287.  
  3288.  
  3289.  
  3290.  
  3291.  
  3292.  
  3293.  
  3294.  
  3295.  
  3296.        ──────────────────────────────────────────────────────────────────────
  3297.        June 6, 1991                                                   Page 52
  3298.  
  3299.  
  3300.  
  3301.                            Inside TURBO Pascal Unit Files            
  3302.        ──────────────────────────────────────────────────────────────────────
  3303.  
  3304.        10. INFERENCES DRAWN FROM ANALYSES
  3305.  
  3306.  
  3307.        I have learned much about Turbo Pascal .EXE files from poring over the
  3308.        output of  the supplied program.  It is possible to learn how to build
  3309.        smaller .EXE  files after  contemplating the  structure of Unit files.
  3310.        It is also possible to avoid certain troublesome anomalies in the code
  3311.        if one  can see  just what  Turbo  Pascal  does  when  certain  switch
  3312.        declaratives are in effect.
  3313.  
  3314.  
  3315.  
  3316.        10.1 LINKER GRANULARITY
  3317.  
  3318.  
  3319.        The Linker  appears to  be able  to resolve  any code or data fragment
  3320.        with a  resolution that  matches the  granularity of the various "map"
  3321.        tables in  the unit  file.   The Code  Map, the CONST DSeg Map and the
  3322.        GLOBAL VAR  Map each  map things that can be included in the .EXE file
  3323.        if referenced.   Conversely,  these things can also be excluded if not
  3324.        referenced.   Turbo Pascal manuals have been just a little vague about
  3325.        how "smart"  the "Smart Linker" actually is but the granularity of the
  3326.        maps implies the extent of that "smartness".  Assuming the linker does
  3327.        in fact  take advantage  of this information and act on it, then we as
  3328.        programmers can  have a  bit more  control over  the elements included
  3329.        from Unit  Files.  This control can extend to GLOBAL VAR's that may be
  3330.        used in particular circumstances, or not at all in others.
  3331.  
  3332.        It seems  that CONST  DSeg and  GLOBAL VAR Map entries are constructed
  3333.        for each  TYPED CONST  or VAR  "Declaration Part"  encountered in  the
  3334.        Pascal source  code.   Thus, "Toolbox" type units can have their Typed
  3335.        CONST's and  GLOBAL VAR's partitioned along usage lines dedicated to a
  3336.        small group  of Procedures or Functions so that they only get included
  3337.        if the  appropriate Procedures  or Functions  are  referenced  or  are
  3338.        explicitly referenced by the some external program.
  3339.  
  3340.  
  3341.  
  3342.        10.2 FLOATING-POINT EMULATION
  3343.  
  3344.  
  3345.        Floating-Point emulation  has some  tricky cases  -- particularly when
  3346.        the In-Line  Assembler is  used.  As noted earlier, the implementation
  3347.        of Floating-Point  Emulation is  the responsibility of the SYSTEM unit
  3348.        in the  MS-DOS version  and of  WIN87EM in  the WINDOWS  version.  The
  3349.        state of the {$G±} directive toggle has an impact in these cases.
  3350.  
  3351.  
  3352.  
  3353.  
  3354.  
  3355.  
  3356.  
  3357.  
  3358.  
  3359.  
  3360.        ──────────────────────────────────────────────────────────────────────
  3361.        June 6, 1991                                                   Page 53
  3362.  
  3363.  
  3364.  
  3365.                            Inside TURBO Pascal Unit Files            
  3366.        ──────────────────────────────────────────────────────────────────────
  3367.  
  3368.        It would  appear that  80286 code  generation  changes  the  way  that
  3369.        floating-point instructions  are generated  since the 80287 is implied
  3370.        as the  co-processor chip.   In  this case,  the programmer  has  fine
  3371.        control over  the timing of WAIT instructions since 80287 instructions
  3372.        don't automatically get prefixed by WAIT ops.  When 8087 code is being
  3373.        generated, these  WAIT instructions are produced for 8087 instructions
  3374.        since the  8087 requires  it.   This doesn't  happen when  the code is
  3375.        targeted at  the 80287.   So far, so good.  However, EMULATION of such
  3376.        code gets trickier.
  3377.  
  3378.  
  3379.  
  3380.        10.2.1 VERSION 6.0 COMPILER FOR MS-DOS
  3381.  
  3382.  
  3383.        It seems that the {$E±} directive doesn't work like it did in previous
  3384.        versions.   All code  produced in 8087 mode seems to be emulated code.
  3385.        I haven't  found a way to get 8087 code generated if the compiler runs
  3386.        on a  machine that  doesn't have  a co-processor.   It may be that the
  3387.        directive works  as documented  if a  co-processor is available on the
  3388.        machine the compiler runs on.
  3389.  
  3390.  
  3391.  
  3392.        10.2.2 VERSION 1.0 COMPILER FOR WINDOWS
  3393.  
  3394.  
  3395.        It seems  that the  WIN87EM DLL  in WINDOWS either needs to be able to
  3396.        service 80287  code via  Hardware Interrupt  07H, or  the  application
  3397.        needs to  be able  to adapt itself to missing co-processor situations.
  3398.        This is  implied by  the Emulation  Fix-Ups discussed  earlier.  These
  3399.        fix-ups are  produced when 8087 code is being generated since the WAIT
  3400.        prefix on  an instruction  provides space  for loader patching.  Since
  3401.        WAIT prefixes  are not  automatically produced  for 80287 instructions
  3402.        (except for  FWAIT), some other mechanism is needed.  I don't know how
  3403.        this situation is handled unless WIN87EM also services Interrupt 07H.
  3404.  
  3405.  
  3406.  
  3407.  
  3408.  
  3409.  
  3410.  
  3411.  
  3412.  
  3413.  
  3414.  
  3415.  
  3416.  
  3417.  
  3418.  
  3419.  
  3420.  
  3421.  
  3422.  
  3423.  
  3424.        ──────────────────────────────────────────────────────────────────────
  3425.        June 6, 1991                                                   Page 54
  3426.  
  3427.  
  3428.  
  3429.                            Inside TURBO Pascal Unit Files            
  3430.        ──────────────────────────────────────────────────────────────────────
  3431.  
  3432.        11. APPLICATION NOTES
  3433.  
  3434.  
  3435.        One of the more obvious applications of this information would seem to
  3436.        be in the area of a Cross-Reference Generator.
  3437.  
  3438.        There is  a very  fine example  of such a program in the public domain
  3439.        that was  written by  Mr. R. N. Wisan called  "PXL".  This program has
  3440.        been around since the days of Turbo Pascal Version 1.  The program has
  3441.        been continually enhanced by the author in the way of features and for
  3442.        support of the newer Turbo Pascal versions.  It does not however solve
  3443.        the problem  of telling  one which  unit contains  the definition of a
  3444.        given symbol.   In fairness to "PXL" however, this is no small problem
  3445.        since the  format of  .TPU files  keeps changing  (Turbo 6.0 Units are
  3446.        not object-code  compatible with  Turbo 5.x  Units, and  so on...) and
  3447.        Mr. Wisan probably has more than enough other projects to keep himself
  3448.        occupied.
  3449.  
  3450.        However, for  the user who is willing to work a little (maybe a lot?),
  3451.        this document would seem to provide the information needed to add such
  3452.        a function to his own pet cross-reference generator.
  3453.  
  3454.        Further, with  SIGNIFICANTLY more  effort, it should be possible to do
  3455.        much of  the job of de-compilation -- provided the DEBUG dictionary is
  3456.        present.   At the very least, most declarations should be recoverable.
  3457.        It's another  thing entirely  to try  to reconstruct  plausable  TURBO
  3458.        Pascal code  from the CSegs.  This would be a formidable task and lots
  3459.        of knowledge  about TURBO's code generators would have to be acquired.
  3460.        At present, the only way I know to get this information is to have the
  3461.        run-time library  source codes and then work-work-work at testing code
  3462.        produced by  the compiler  for a  huge number of test case units.  You
  3463.        have to  want to  do this really badly in order to invest the time.  I
  3464.        am not that tired of living.
  3465.  
  3466.        Finally, code-tuning is not really so tedious an exercise as one might
  3467.        imagine.   The disassembler  makes it possible to experiment with many
  3468.        variants of  specific source code at the unit level and to observe the
  3469.        effect on  object code  generated.   With practice,  there are certain
  3470.        coding practices  one can  avoid such  as indescriminate  use  of  the
  3471.        "WITH" statement in Pascal (generates extra pointers and stack usage).
  3472.        A really  simple way  of checking a code proposal is to create a small
  3473.        test unit  and fill  it with  sample coding.  Disassembly of that unit
  3474.        will show what code is produced.  This can be a rewarding exercise!
  3475.  
  3476.  
  3477.  
  3478.  
  3479.  
  3480.  
  3481.  
  3482.  
  3483.  
  3484.  
  3485.  
  3486.  
  3487.  
  3488.        ──────────────────────────────────────────────────────────────────────
  3489.        June 6, 1991                                                   Page 55
  3490.  
  3491.  
  3492.  
  3493.                            Inside TURBO Pascal Unit Files            
  3494.        ──────────────────────────────────────────────────────────────────────
  3495.  
  3496.        12. ACKNOWLEDGEMENTS
  3497.  
  3498.  
  3499.        This project  would have  been totally  infeasible without  the aid of
  3500.        some very  fine tools.  As it was, several hundred man hours have been
  3501.        expended on  it and  as you can see, there are a few unresolved issues
  3502.        that have  been (graciously)  left for  others to  address.  The tools
  3503.        used by this author consisted of:
  3504.  
  3505.        Turbo Pascal for Windows by Borland International
  3506.  
  3507.        Turbo Pascal 6.0 Professional by Borland International
  3508.  
  3509.        Microsoft WORD (version 5.5)
  3510.  
  3511.        LIST (version 7.5) by Vernon D. Buerg
  3512.  
  3513.        the DEBUG utility in MS-DOS Version 3.3.
  3514.  
  3515.        PARADOX 3.5 by Borland International
  3516.  
  3517.        QUATTRO PRO Version 2.0 by Borland International
  3518.  
  3519.        TURBO ASSEMBLER 2.0 by Borland International
  3520.  
  3521.        (PARADOX and QUATTRO PRO were used for data collection and analysis in
  3522.        the course of coding the recognizer tables for the disassembler unit.)
  3523.  
  3524.        The references  listed were of great value in this project.  [Intel85]
  3525.        was a valuable source of information about coprocessor instructions as
  3526.        well as offering hints about the differences between the 8086/8088 and
  3527.        the 80286.   The  [Borland] TASM  manuals offered  further info on the
  3528.        80186.     [Nelson]  provided  presentations  of  well-organized  data
  3529.        directed at the problem of disassembly but the tables were flawed by a
  3530.        number of  errors which  crept into my databases and which caused much
  3531.        of the extra debugging effort.  [Intel89] offered valuable insights on
  3532.        the 80386  addressing schemes  as well  as the 32-bit data extensions.
  3533.        Finally,  [Brown]   provided  valuable  clues  on  the  Floating-Point
  3534.        emulators used  by Borland  (and Microsoft?).   As  you can  see,  the
  3535.        amount of  hard information  available to me on this project was quite
  3536.        limited since I am unaware of any other existing body of literature on
  3537.        this subject.
  3538.  
  3539.        Finally, I  am grateful  to Mr.  Anders Hejlsberg (Borland's Principal
  3540.        Architect for TURBO PASCAL) for the time he spent discussing "cabbages
  3541.        and kings" with me.  TURBO PASCAL owes much of its syntactic style and
  3542.        elegance to his efforts and good judgement.
  3543.  
  3544.  
  3545.  
  3546.  
  3547.  
  3548.  
  3549.  
  3550.  
  3551.  
  3552.        ──────────────────────────────────────────────────────────────────────
  3553.        June 6, 1991                                                   Page 56
  3554.  
  3555.  
  3556.  
  3557.                            Inside TURBO Pascal Unit Files            
  3558.        ──────────────────────────────────────────────────────────────────────
  3559.  
  3560.                                    13. REFERENCES
  3561.  
  3562.  
  3563.        [Borland], TURBO  PASCAL   FOR  WINDOWS  Programmer's  Guide,  Borland
  3564.                   International, 1991.
  3565.  
  3566.        [Borland], TURBO ASSEMBLER  REFERENCE  GUIDE,  Borland  International,
  3567.                   1988.
  3568.  
  3569.        [Borland], TURBO ASSEMBLER USER'S GUIDE, Borland International, 1988.
  3570.  
  3571.        [Borland]  TURBO PASCAL  6.0 PROGRAMMING GUIDE, Borland International,
  3572.                   1990.
  3573.  
  3574.        [Borland]  TURBO  PASCAL   LIBRARY  REFERENCE   Version  6.0,  Borland
  3575.                   International, 1990.
  3576.  
  3577.        [Borland]  TURBO   PASCAL    USER'S   GUIDE   Version   6.0,   Borland
  3578.                   International, 1990.
  3579.  
  3580.        [Brown],   INTER191.ARC, Ralf Brown, 1991
  3581.  
  3582.        [Intel85], iAPX 286  PROGRAMMER'S REFERENCE  MANUAL INCLUDING THE iAPX
  3583.                   286 NUMERIC  SUPPLEMENT, Intel  Corporation,  1985,  (order
  3584.                   number 210498-003).
  3585.  
  3586.        [Intel89], 386  SX MICROPROCESSOR PROGRAMMER'S REFERENCE MANUAL, Intel
  3587.                   Corporation, 1989, (order number 240331-001).
  3588.  
  3589.        [Nelson]   THE 80386  BOOK:   ASSEMBLY LANGUAGE PROGRAMMER'S GUIDE FOR
  3590.                   THE 80386, Ross P. Nelson, Microsoft Press, 1988.
  3591.  
  3592.        [Scanlon], 80286  ASSEMBLY   LANGUAGE  ON  MS-DOS  COMPUTERS,  Leo  J.
  3593.                   Scanlon, Brady 1986.
  3594.  
  3595.  
  3596.  
  3597.  
  3598.  
  3599.  
  3600.  
  3601.  
  3602.  
  3603.  
  3604.  
  3605.  
  3606.  
  3607.  
  3608.  
  3609.  
  3610.  
  3611.  
  3612.  
  3613.  
  3614.  
  3615.  
  3616.        ──────────────────────────────────────────────────────────────────────
  3617.        June 6, 1991                                                   Page 57
  3618.  
  3619.  
  3620.  
  3621.                                      14. INDEX
  3622.  
  3623.  
  3624.  
  3625.        .OBJ file........14, 35, 37, 39       Hash.............13, 14, 15, 16,
  3626.        .RES file........39                                    17, 18, 19, 20,
  3627.        .TPL file........8, 16, 45, 46,                        25, 30, 31, 48
  3628.                         52
  3629.        .TPU                                  Include..........39, 40
  3630.          file...........7, 9, 13, 16,        Interface........7, 13, 14, 15,
  3631.                         27, 45, 46, 52,                       16, 17, 18, 19,
  3632.                         55                                    26
  3633.            size.........16                   Interrupt 07H....54
  3634.          SYSTEM.........8, 18, 19, 21,
  3635.                         27, 49, 52           Library..........45
  3636.                                              Locator
  3637.        {$E±}............54                     LG.............9, 12, 21, 23,
  3638.        {$G±}............53                                    26, 27, 30, 31,
  3639.                                                               32, 33, 34
  3640.        80286............54                     LL.............9, 13, 18, 26,
  3641.        80287............44, 54                                35
  3642.        80387............44                     offset.........9, 11, 12, 22,
  3643.        8087.............42, 44, 54                            24, 25, 31, 35,
  3644.                                                               36, 40, 41, 42
  3645.        Attribute
  3646.          ABSOLUTE.......9                    Method...........24
  3647.          EXTERNAL.......24, 35                 CONSTRUCTOR....24
  3648.                                                DESTRUCTOR.....24
  3649.        Call Model                              Self...........22
  3650.          ASSEMBLER......24
  3651.          Dynamic........24                   Operand offset...42
  3652.          FAR............24
  3653.          INLINE.........24                   Parameter........20, 23, 25, 34
  3654.          INTERRUPT......24                   PROC.............7, 13, 14, 24,
  3655.        CONST............7, 13, 14, 15,                        35, 36, 40, 42,
  3656.                         22, 31, 37, 40,                       47
  3657.                         41, 42, 47
  3658.        Constraint.......33, 34               RunError.........47
  3659.        CSeg.............7, 13, 14, 35,
  3660.                         36, 37, 39, 40,      SEGMENT..........42
  3661.                         41, 42, 47           Signature........7, 26
  3662.                                              Stub.............9, 20, 23
  3663.        Defining block...37, 38                 sSxx...........24
  3664.        Directive........14, 15, 16, 24,      SYSTEM.TPS.......8, 19
  3665.                         35, 39, 40
  3666.        DLL..............7, 13, 38, 42        TPW..............45, 52
  3667.        DMT..............14, 15, 24, 31,      TURBO............45, 52
  3668.                         37                   Type Descriptor..21, 23, 26, 27,
  3669.                                                               28, 30, 31, 32,
  3670.        Emulation........53                                    33, 34, 49
  3671.        Emulator.........42, 43
  3672.        External.........9, 35, 37, 42,       VAR..............38, 47
  3673.                         52                   VMT..............14, 15, 25, 31,
  3674.                                                               37
  3675.        FWAIT............54
  3676.                                              WIN87EM..........42, 44, 53, 54
  3677.        Granularity......53